-
Java์์ ๋ฐ์ดํฐ๋ฒ ์ด์ค์ SELECT ์ฟผ๋ฆฌ์ ๋ํด Lock๊ณผ Unlock์ ์ฌ์ฉํ๋ ๋ฐฉ๋ฒ์ ๋ฐ์ดํฐ๋ฒ ์ด์ค ์์คํ ๊ณผ ์ฟผ๋ฆฌ์ ์ค์ ์ ๋ฐ๋ผ ๋ฌ๋ผ์ง๋๋ค. ์ผ๋ฐ์ ์ผ๋ก SELECT ์์ฒด๋ ๋ฐ์ดํฐ๋ฒ ์ด์ค์์ ์ ๊ธ์ ์ ๋ฐํ์ง ์์ง๋ง, ํธ๋์ญ์ ์ด๋ ์ฟผ๋ฆฌ ํํธ๋ฅผ ์ฌ์ฉํ์ฌ ์ ๊ธ ๋์์ ์ ์ดํ ์ ์์ต๋๋ค. ์๋์ ๋ช ๊ฐ์ง ๋ฐฉ๋ฒ์ ์ค๋ช ํฉ๋๋ค.
1. ํธ๋์ญ์ ์ ์ฌ์ฉํ Lock ์ ์ด
ํธ๋์ญ์ ์ ํตํด SELECT ๋ฌธ์ด ์คํ ์ค์ธ ๋์ ๋ค๋ฅธ ์์ ์ด ๋ฐ์ดํฐ์ ์ ๊ทผํ์ง ๋ชปํ๋๋ก ์ ๊ธ์ ์ค์ ํ ์ ์์ต๋๋ค.
์์ ์ฝ๋:
import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.ResultSet; public class DatabaseLockExample { public static void main(String[] args) { String url = "jdbc:mysql://localhost:3306/your_database"; String user = "your_username"; String password = "your_password"; try (Connection connection = DriverManager.getConnection(url, user, password)) { // Auto-commit ๋นํ์ฑํ connection.setAutoCommit(false); // SELECT ... FOR UPDATE (ํ ์ ๊ธ ์ค์ ) String sql = "SELECT * FROM your_table WHERE id = ? FOR UPDATE"; try (PreparedStatement preparedStatement = connection.prepareStatement(sql)) { preparedStatement.setInt(1, 1); // ID ๊ฐ ๋ฐ์ธ๋ฉ ResultSet resultSet = preparedStatement.executeQuery(); while (resultSet.next()) { System.out.println("Data: " + resultSet.getString("your_column")); } // ์์ ํ ์ปค๋ฐ connection.commit(); } } catch (Exception e) { e.printStackTrace(); } } }์ค๋ช :
FOR UPDATE๋ ํด๋น ํ์ ์ ๊ทธ๊ณ , ๋ค๋ฅธ ํธ๋์ญ์ ์ด ์์ ํ์ง ๋ชปํ๋๋ก ํฉ๋๋ค.- ํธ๋์ญ์ ์ ์ปค๋ฐํ๊ฑฐ๋ ๋กค๋ฐฑํ๋ฉด ์ ๊ธ์ด ํด์ ๋ฉ๋๋ค.
2. ์ฟผ๋ฆฌ ํํธ๋ฅผ ์ฌ์ฉํ Lock ์ ์ด
๋ฐ์ดํฐ๋ฒ ์ด์ค์ ๋ฐ๋ผ SELECT ์ฟผ๋ฆฌ์ ํํธ๋ฅผ ์ถ๊ฐํ์ฌ ์ ๊ธ ๋์์ ์ง์ ํ ์ ์์ต๋๋ค. ์๋ฅผ ๋ค์ด, MySQL์์
LOCK IN SHARE MODE๋๋FOR UPDATE๋ฅผ ์ฌ์ฉํ ์ ์์ต๋๋ค.CreatedWed, 26 Mar 2025 11:25:45 +0900 -
Spring Boot JPA์์
@Transactional์ฌ์ฉ๋ฒSpring Boot JPA์์
@Transactional์ด๋ ธํ ์ด์ ์ ํธ๋์ญ์ ๋ฒ์ ๋ด์์ ๋ฐ์ดํฐ๋ฒ ์ด์ค ์์ ์ ์คํํ๊ณ , ์คํจ ์ ๋กค๋ฐฑํ๋ ๊ธฐ๋ฅ์ ์ ๊ณตํ๋ ์ค์ํ ์์์ ๋๋ค.
1.
@Transactional๊ธฐ๋ณธ ์ฌ์ฉ๋ฒSpring์
@Transactional์ ์ฌ์ฉํ๋ฉด ํ๋์ ๋ฉ์๋์์ ์ฌ๋ฌ ๊ฐ์ JPA ์์ (์กฐํ, ์ ์ฅ, ์์ , ์ญ์ ๋ฑ)์ ์ํํ ๋ ํธ๋์ญ์ ์ ์๋์ผ๋ก ๊ด๋ฆฌํ ์ ์์ต๋๋ค.import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @Service public class MemberService { private final MemberRepository memberRepository; public MemberService(MemberRepository memberRepository) { this.memberRepository = memberRepository; } @Transactional public void updateMember(Long id, String name) { Member member = memberRepository.findById(id) .orElseThrow(() -> new IllegalArgumentException("Member not found")); member.setName(name); // JPA ์์์ฑ ์ปจํ ์คํธ์ ์ํด ์๋์ผ๋ก ์ ๋ฐ์ดํธ๋จ } }@Transactional์ ์ฌ์ฉํ๋ฉด, ๋ฉ์๋ ์คํ ์ค ์์ธ๊ฐ ๋ฐ์ํ๋ฉด ๋กค๋ฐฑ๋๋ฉฐ, ์ฑ๊ณตํ๋ฉด ์๋์ผ๋ก ์ปค๋ฐ๋ฉ๋๋ค.member.setName(name);์ ํธ์ถํ๋ฉด JPA์ ๋ณ๊ฒฝ ๊ฐ์ง(dirty checking) ๋๋ถ์save()๋ฅผ ๋ช ์์ ์ผ๋ก ํธ์ถํ์ง ์์๋ ์ ๋ฐ์ดํธ๋ฉ๋๋ค.
2. ์ฝ๊ธฐ ์ ์ฉ ํธ๋์ญ์ (
@Transactional(readOnly = true))readOnly = true๋ฅผ ์ค์ ํ๋ฉด ์ฑ๋ฅ ์ต์ ํ๋ฅผ ํ ์ ์์ต๋๋ค.CreatedWed, 26 Mar 2025 11:21:45 +0900 -
Spring Boot JPA์์ @Transactional ์ต์ ์ ๋ฆฌ
Spring Boot JPA์์
@Transactional์ ํธ๋์ญ์ ์ฒ๋ฆฌ๋ฅผ ์ํด ์ฌ์ฉํ๋ ๋งค์ฐ ์ค์ํ ์ด๋ ธํ ์ด์ ์ด์์. ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ์ผ๊ด์ฑ๊ณผ ๋ฌด๊ฒฐ์ฑ์ ์ ์งํ๊ธฐ ์ํด ์ฌ๋ฌ ์์ ์ ํ๋์ ํธ๋์ญ์ ์ผ๋ก ๋ฌถ์ด ์คํํ ๋ ์ฌ์ฉํ์ฃ . ์๋์ ์ฌ์ฉ๋ฒ์ ์ ๋ฆฌํด๋ณผ๊ฒ์.
๐ ๊ธฐ๋ณธ ์ฌ์ฉ๋ฒ
import org.springframework.transaction.annotation.Transactional; @Service public class MemberService { @Transactional public void joinMember(Member member) { memberRepository.save(member); // ์์ธ ๋ฐ์ ์ ์ ์ฒด ํธ๋์ญ์ ๋กค๋ฐฑ } }@Transactional์ ๋ฉ์๋์ ๋ถ์ด๋ฉด ํด๋น ๋ฉ์๋ ์์ ์์ ์ด ํ๋์ ํธ๋์ญ์ ์ผ๋ก ์ฒ๋ฆฌ๋ผ์.- ๋ฐํ์ ์ค ์์ธ๊ฐ ๋ฐ์ํ๋ฉด ์๋์ผ๋ก ๋กค๋ฐฑ๋ผ์. (๊ธฐ๋ณธ์ ์ผ๋ก unchecked exception์ผ ๋๋ง ๋กค๋ฐฑ)
๐ ํด๋์ค ๋ ๋ฒจ์ ์ฌ์ฉ
@Transactional @Service public class MemberService { public void method1() { // ํธ๋์ญ์ ์ ์ฉ๋จ } public void method2() { // ํธ๋์ญ์ ์ ์ฉ๋จ } }- ํด๋์ค ์ ์ฒด์ ํธ๋์ญ์ ์ ๊ฑธ ์ ์์ด์. ๋จ, ๋ฉ์๋์ ๊ฐ๋ณ์ ์ผ๋ก ์ค์ ๋ ๊ฒ ์ฐ์ ์ ์ฉ๋ฉ๋๋ค.
๐ rollbackFor ์ต์
๊ธฐ๋ณธ์ ์ผ๋ก
RuntimeException๊ณผ ๊ทธ ํ์ ํด๋์ค๋ง ๋กค๋ฐฑ ๋์์ผ๋ก ๊ฐ์ฃผ๋ผ์. ๋ง์ฝ ์ฒดํฌ ์์ธ(Exception)๋ ๋กค๋ฐฑํ๊ณ ์ถ๋ค๋ฉด:CreatedWed, 26 Mar 2025 11:15:45 +0900 -
Java์์ Redis๋ฅผ ์ฌ์ฉํ ๋
CRUD Repository์RedisTemplate์ ๊ฐ๊ฐ ๋ค๋ฅธ ์์ค์ ์ถ์ํ๋ฅผ ์ ๊ณตํ๋ ๋ฐฉ์์ ๋๋ค. ์ฃผ์ ์ฐจ์ด์ ์ ๋ค์๊ณผ ๊ฐ์ต๋๋ค:
โ 1. CRUD Repository (Spring Data Redis)
RedisRepository,CrudRepository,PagingAndSortingRepository๋ฑ๊ณผ ๊ฐ์ด Spring Data๊ฐ ์ ๊ณตํ๋ Repository ์ธํฐํ์ด์ค๋ฅผ ์ฌ์ฉํ๋ ๋ฐฉ์์ ๋๋ค.๐น ์ฅ์
- ๋์ ์ถ์ํ ์์ค: ๋จ์ํ CRUD ์์ ์ ์ธํฐํ์ด์ค๋ก ์ ์ํ๊ธฐ๋ง ํ๋ฉด, ๊ตฌํ ์์ด ์๋์ผ๋ก ๋์.
- ๊ฐ๋ฐ ์๋ ๋น ๋ฆ: ๋ฐ๋ณต์ ์ธ ๋ก์ง ์ค์ผ ์ ์์ (
findById,save,delete๋ฑ ๊ธฐ๋ณธ ์ ๊ณต). - Spring Data์ ๊ธฐ๋ฅ์ ํ์ฉ ๊ฐ๋ฅ (์: ์ฟผ๋ฆฌ ๋ฉ์๋, ํ์ด์ง ๋ฑ).
๐น ๋จ์
- ์ธ๋ฐํ ์ ์ด ์ด๋ ค์: ๋ณต์กํ ๋ฐ์ดํฐ ๊ตฌ์กฐ๋ ์ปค์คํ ๋ก์ง์ ๊ตฌํํ๊ธฐ ์ด๋ ค์.
- ์ง๋ ฌํ ๋ฐฉ์ ๊ณ ์ : ๊ธฐ๋ณธ์ ์ผ๋ก JDK ์ง๋ ฌํ๋ฅผ ์ฌ์ฉํ๊ณ , ์ปค์คํฐ๋ง์ด์ง ํ๋ ค๋ฉด ์ค์ ํ์.
๐น ์์
public interface UserRedisRepository extends CrudRepository<User, String> { Optional<User> findByUsername(String username); }
โ 2. RedisTemplate
Spring์์ ์ ๊ณตํ๋ ์ ์์ค API๋ก, ํค-๊ฐ ์ ์ฅ์๋ก์ Redis๋ฅผ ์ ์ฐํ๊ฒ ๋ค๋ฃฐ ์ ์์.
CreatedWed, 26 Mar 2025 11:11:03 +0900 -
feign client ์ฌ์ฉํ 1 - ์๋ ์๋ฒ๊ฐ ์ฌ๋ฌ๋ ์ผ๋ ๋๋ค ํธ์ถ
load balancing ๋๊ณ ์๋ ์๋์ธก์ ๋ฒ๊ฐ์๊ฐ๋ฉด์ ํธ์ถํ๋ ๋ฐฉ๋ฒ
- build.gradle
... dependencies { implementation 'org.springframework.cloud:spring-cloud-starter-openfeign' } ...- application.yml
# ์๋ ์ธก์์ 3๊ฐ์ ์๋ฒ LB๋๊ณ ์์ ๋ other-party-url: - 123.456.789.001 - 123.456.789.002 - 123.456.789.003- ServerProperties.java
@Setter @Getter @Configuration @ConfigurationProperties(prefix = "other-party-url") public class OtherServerProperties { private List<String> serverUris; }- FeignConfig.java
@RequiredArgsConstructor public class OtherServerFeignConfig { private final OtherServerProperties otherServerProperties; private final AtomicInteger counter = new AtomicInteger(0); @Bean public RequestInterceptor randomServerInterceptor() { return requestTemplate -> { List<String> serverUris = otherServerProperties.getServerUris(); int index = counter.getAndIncrement() % serverUris.size(); String selectedUrl = serverUris.get(index); requestTemplate.target(selectedUrl); }; } }- FeignClient interface
@FeignClient(name = "your-server", configuration = OtherServerFeignConfig.class) public interface OtherServerFeignClientV1 { ... }CreatedWed, 26 Mar 2025 08:37:45 +0900 -
๐ DispatcherServlet ์ด๊ธฐํ ๊ณผ์
1. ServletContainer๊ฐ DispatcherServlet์ ๋ก๋ฉ
Spring Boot ์ฑ์ ์คํํ๋ฉด, ๋ด์ฅ ํฐ์บฃ์ด ๋จ๊ณ ์๋ ๊ณผ์ ์ด ์์๋ผ์:
- Spring Boot๊ฐ ์๋์ผ๋ก
DispatcherServlet์ ์๋ธ๋ฆฟ์ผ๋ก ๋ฑ๋กํจ (/๋งคํ) DispatcherServlet์ ์ฌ์คHttpServlet์ ์์๋ฐ์ ํด๋์ค- ์ด๋ ํธ์ถ๋๋ ๋ฉ์๋๊ฐ โ
init()โ ๊ทธ ์์์initServletBean()์คํ๋จ
2. WebApplicationContext ์์ฑ ๋ฐ ์ด๊ธฐํ
DispatcherServlet์ ์์ ์ Spring WebApplicationContext๋ฅผ ๊ฐ์ง๊ณ ์์- ์ด WebApplicationContext๋
@Controller,@RestController,@Service,@Repository๋ฑ์ด ๋ฑ๋ก๋ ๊ณต๊ฐ
GenericWebApplicationContext โ AnnotationConfigWebApplicationContext โ WebApplicationContext โ DispatcherServlet์ด ์ฌ์ฉDispatcherServlet์ ์ด context๋ฅผ ํตํด ๋น์ ์ฐพ๊ณ , ๋ผ์ฐํ ์ ์ํํจCreatedWed, 26 Mar 2025 08:20:45 +0900 - Spring Boot๊ฐ ์๋์ผ๋ก