Spring Framework

@Async스프링에서는 @Async 어노테이션을 사용하면 비동기로 메서드를 호출할 수 있다.@Async 어노테이션은 Spring AOP로 동작하며 요청 스레드와 별개의 스레드에서 해당 메서드를 비동기로 수행할 수 있게 한다. ThreadPoolTaskExecutor 빈 등록@EnableAsync 어노테이션도 같이 붙여야 @Async가 동작한다.근데 왜 ThreadPoolTaskExecutor 빈을 등록하라는 걸까?  기본적으로 @EnableAsync 어노테이션을 사용하면 TaskExecutor 타입의 빈을 찾고 해당 빈을 통해 비동기를 처리한다.만약 개발자가 직접 커스텀하게 등록한 TaskExecutor 빈이 존재하지 않으면 디폴트로 SimpleAsyncTaskExecutor를 사용하게 되는데, Simp..
여러 스레드가 동시에 하나의 데이터에 접근해서 값을 수정하는 경우 race condition(경쟁 조건)이 발생할 수 있다. 이를 해결하기 위한 방법에는 여러가지가 있는데 이번 포스팅에는 Optimistic Lock을 활용하여 해결해 보도록 한다. 데이터베이스 동시성 이슈 해결하기 시리즈 1. Optimistic Lock 2. Pessimistic Lock 3. Named Lock 4. Redis Lettuce 5. Redis Redisson Optimistic Lock(낙관적 락) 낙관적 락은 여러 사용자가 동시에 같은 데이터를 수정하는 경우가 드물다고 가정할 때 주로 사용한다. 따라서 Lock을 걸지 않고 충돌이 발생하면 그때마다 엔티티의 버전을 비교하여 동시성 이슈를 해결하는 방식이다. 즉, DB ..
@Transactional 어노테이션과 @PostContruct 어노테이션을 함께 사용하면 @Transactional 어노테이션이 적용되지 않는다.초기화가 먼저 일어난 이후 트랜잭션 AOP가 동작하기 때문이다. @SpringBootTestpublic class InitTxTest { @Test public void test() throws Exception { System.out.println("TEST"); } @TestConfiguration static class InitTxTestConfig { @Bean Hello hello() { return new Hello(); } } static c..
스프링에서는 @Transactional 어노테이션이 붙은 메서드가 진짜 객체에서 호출하는지, 프록시 객체에서 호출하는지 판단해서 로직을 작성하는 것이 중요하다. 아래의 잘못된 테스트 코드를 살펴보고 트랜잭션이 적용되지 않는 원인을 알아보도록 하자. @SpringBootTest public class InternalCallV1Test { @Autowired CallService callService; @Test public void printProxy() throws Exception { System.out.println("callService = " + callService.getClass()); } @Test public void internalCall() throws Exception { callSe..
벌크 연산은 데이터를 한번에 수정하는 것을 의미한다. 벌크 연산은 1차 캐시를 거치지 않고 DB로 바로 접근하여 SQL을 실행하여 값을 수정한다. 따라서, 1차 캐시를 반드시 초기화 해야 한다. 1차 캐시를 초기화하지 않으면 벌크 연산으로 인해 수정된 DB 데이터와 1차 캐시에 있는 데이터의 정합성이 깨지게 된다. 순수 JPA를 사용하여 벌크 연산하기 @Repository public class MemberJpaRepository { public int bulkAgePlus(int age) { return entityManager.createQuery( "update Member m set m.age = m.age + 1 where m.age >= :age" ) .setParameter("age", ag..
이번 포스팅에서는 JPA N+1 문제 해결 방법에 세 가지를 알아본다. N+1 문제란? N+1 문제는 한 번의 select 쿼리를 실행했을 때 N+1번의 select 쿼리가 실행되는 것을 의미한다. N+1 문제를 강제로 발생시켜보자. Member 클래스와, Team 클래스는 아래와 같다. // Member.java @Entity @Getter @Setter @NoArgsConstructor(access = AccessLevel.PROTECTED) @ToString(of = {"id", "username", "age"}) public class Member { @Id @GeneratedValue @Column(name = "member_id") private Long id; private String na..
@JoinColumn은 다대일 또는 일대다 연관관계를 매핑할 때 사용한다. 아래의 Member 클래스와 Order 클래스를 살펴보자. @Entity @Getter @Setter public class Member { @Id @GeneratedValue @Column(name="member_id") private Long id; @OneToMany(mappedBy = "member") private List orders = new ArrayList(); } @Entity @Table(name="orders") @Getter @Setter public class Order { @Id @GeneratedValue @Column(name="order_id") private Long id; @ManyToOne(f..
두 가지의 예외 상황을 통해 인터셉터의 afterCompletion 메서드와 ExceptionResolver 작동여부 확인해보겠습니다. 상황 1. 컨트롤러에서 RuntimeException이 발생 @RequestMapping(value = "/error-test", method = RequestMethod.GET) public void errorTest(HttpServletRequest req) { throw new NullPointerException("NPE 발생"); // RuntimeException을 상속받은 Exception } 1번 상황에서는 ExceptionResolver가 작동하고 afterCompletion에는 Exception 객체에 null이 반환됩니다. @Override publi..
ctp102
'Spring Framework' 카테고리의 글 목록