스프링 347

48. 스프링 트랜잭션 전파

트랜잭션이 둘 이상 있을 때 라던지, 아니면 저번에 트랜잭션 프록시에서 트랜잭션 아닌 거에서 트랜잭션을 호출했을 때 어떻게 동작하는 지 알아 봄. @Slf4j @SpringBootTest public class BasicTxTest { @Autowired PlatformTransactionManager txManager; @Test void commit(){ log.info("트랜잭션 시작"); TransactionStatus status = txManager.getTransaction(new DefaultTransactionAttribute()); log.info("트랜잭션 커밋 시작"); txManager.commit(status); log.info("트랜잭션 커밋 완료"); } @Test void ..

47. 트랜잭션과 예외 -활용

체크예외를 커밋하는 이유는 스프링 설계 자체가 비즈니스 예외는 체크예외, 언체크예외는 복구 불가능 한 예외라고 가정하고 설계 됨. 물론 꼭 따를 필요는 없음. 그냥 rollbackFor 이런 거 써도 되고. 비즈니스 예외라는 것은, 예를 들어 잔고부족 같은 거. 보통 이런 건 우리가 따로 비즈니스 적으로 예를 들어 잔고가 부족합니다! 이런 메시지를 클라이언트에게 전해주게 하던지 처리 해야 하니까. 주문데이터를 일단 저장하고, 결제 상태를 대기로 만들고, 고객에게 잔고 부족을 알리는 등. 이렇게 시스템 자체는 문제가 없지만 비즈니스 상황에 대해 있는 문제를 비즈니스 예외. 이런 비즈니스 예외는 굉장히 중요하고 반드시 처리해야 하는 경우가 많아서 체크 예외를 고려. 그래서 보통 예외 구분은 시스템 장애 예외..

46. 트랜잭션과 예외

Default는 런타임예외 발생 시 롤백, 체크예외 발생 시 커밋임. @SpringBootTest public class RollbackTest { @Autowired RollbackService service; @Test void runtimeException(){ assertThatThrownBy(()->service.runtimeException()) .isInstanceOf(RuntimeException.class); } @Test void checkedException(){ assertThatThrownBy(()->service.checkedException()) .isInstanceOf(MyException.class); } @Test void rollbackFor(){ assertThatTh..

44. 트랜잭션 AOP 주의사항 -초기화 시점

스프링 초기화 시점, 에는 트랜잭션 AOP가 적용이 되지 않을 수도 있다. Custom init() 저 부분 인 듯? 그러니까, @PostConstruct가 의존성 주입 이후 우리가 뭔가 초기화? 작업같은 거 해 두고 싶을 때 저거 붙인 메소드 만들면 알아서 실행이 되는데, 만약 @PostConstruct @Transactional 이렇게 있으면 @Transactional이 적용이 되지 않을 수도 있다. 순서가 @PostConstruct 등 초기화가 모두 된 다음에 프록시로써 쓸 수 있다. @SpringBootTest public class InitTxTest { @Autowired Hello hello; @Test public void initTx(){ } @TestConfiguration static..

43. 트랜잭션 AOP 주의사항 2 -프록시 내부호출

스프링 트랜잭션 AOP기능은 public 메소드만 적용 됨. 그리고 이건 실무에서도 쓰는 방법중 하나인데, @Transactional 없는 메소드 -> @Transactional 있는 메소드 이런 식 일시, @Slf4j @SpringBootTest public class InternalCallV2Test { @Autowired CallService callService; @Test void printProxy(){ log.info("callService class={}", callService.getClass()); } @Test void externalCallV2(){ callService.external(); } @TestConfiguration static class InternalCallV1Tes..

42. 트랜잭션 AOP 주의사항 -프록시 내부 호출

트랜잭션이 제대로 적용 안되는 문제, 그로 인하여 default인 오토커밋모드로 커밋되어 rollback을 해도 의도되로 안되는.. 우선 다음 코드를 보자. @Slf4j @SpringBootTest public class InternalCallV1Test { @Autowired CallService callService; @Test void printProxy(){ log.info("callService class={}", callService.getClass()); } @Test void internalCall(){ callService.internal(); } @Test void externalCall(){ callService.external(); } @TestConfiguration static ..

41. 스프링 트랜잭션 우선순위

이게 보니까 우리가 스프링 트랜잭션 한번 배웠긴 했는데 다시 배우는 게 이번에는 좀 더 깊게? 어떻게 일어나는 지 그거 보는거랑 트랜잭션 추가 기능? 트랜잭션에 우리가 @Transactional(옵션이름=값) 이런 식으로 줄 수 있는데, 우선순위라는 게 예를 들어 @Transactional(옵션1 = 값1) class TxClass{ @Transactional(옵션1 = 값2) public void txTest(){ } } 하면 저 값2가 적용된다는 이야기. 사실 더 자세할 수록 그것이 적용된다는 것은 어느정도 프로그래머 입장에서는 통설로 받아들여져서.. @SpringBootTest @Slf4j public class TxLevelTest { @Autowired LevelService service; @..

40. 스프링 트랜잭션 테스트

트랜잭션 가져왔다. 먼저, 테스트 환경에서 로그 보기 위해 testAnnotationProcessor 'org.projectlombok:lombok' testImplementation 'org.projectlombok:lombok' build.gradle에 추가, 그 다음 application.properties에 logging.level.org.springframework.transaction.interceptor = TRACE 로그 중 트랜잭션의 것을 인터셉트 해 오는데 TRACE 레벨을 인터셉트 해 옴 @Slf4j @SpringBootTest public class TxBasicTest { @Autowired BasicService basicService; @Test void proxyCheck()..

39. DB 접근 기술의 조합

딱 정답이 있다곤 할 수 없음. 상황에 맞춰, 사람에 맞춰 하는 게 좋다고 생각. JdbcTemplate, MyBatis는 SQL을 직접 작성해야 하므로, SQL에 익숙한 집단에게 좋음. JPA, 스프링데이터JPA, Querydsl은 배울 필요가 있지만, 생산성이 높아짐. 예를 들어 거의 7~80% 통계쿼리만 작성해야 하는 프로젝트면 MyBatis도 괜찮음. 근데 보통 애플리케이션은 로직과 약간 일부의 통계 보통 이런 식이긴 하다. 그래서 보통 선생님이 추천하는 방식은, JPA, SpringDataJPA, Querydsl을 기본으로 사용하면서, 해결이 잘 안되는 복잡한 쿼리를 직접 짜는게 나을 경우 JdbcTemplate나 MyBatis 등을 함께 사용. 거의 실무에서 95%정도 JPA,SpringDat..

38. 실용적인 구조로 변환

기존 에서 이 구조로 한번 변화시켜 볼 것이다. Service에서 자동으로 생성되는 SpringDataJPA를 직접 쓰면서, Querydsl이 필요한, 복잡한 동적 쿼리가 필요한 것은 저렇게 우리가 구현해 놓은 리포지토리를 쓴다. 즉, 같은 테이블 이지만 리포지토리를 2종류 쓰는 것이다. 여튼, 스프링데이터JPA는 스프링데이터JPA상속받은 인터페이스를 만들어 놓으면, 자동으로 빈에 등록이 되고, Querydsl쓰는 리포지토리는 만들어서, 그 두개를 서비스에서 적절히 사용하면 된다. @Entity //@Table(name="item") public class Item { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; @Co..