728x90
Member
@Entity
@Getter
@Setter
public class Member {
@Id
@GeneratedValue
private Long id;
private String username;
public Member(){
}
public Member(String username) {
this.username = username;
}
}
MemberRepository
@Slf4j
@Repository
@RequiredArgsConstructor
public class MemberRepository {
private final EntityManager em;
@Transactional
public void save(Member member){
log.info("member 저장");
em.persist(member);
}
public Optional<Member> find(String username){
return em.createQuery("select m from Member m where m.username = :username", Member.class)
.setParameter("username", username)
.getResultList().stream().findAny();
}
}
Log
@Entity
@Getter
@Setter
public class Log {
@Id @GeneratedValue
private Long id;
private String message;
public Log(){
}
public Log(String message) {
this.message = message;
}
}
LogRepository
@Slf4j
@Repository
@RequiredArgsConstructor
public class LogRepository {
private final EntityManager em;
@Transactional
public void save(Log logMessage){
log.info("log 저장");
em.persist(logMessage);
if(logMessage.getMessage().contains("로그예외")){
log.info("log 저장시 예외 발생");
throw new RuntimeException("예외 발생");
}
}
public Optional<Log> find(String message){
return em.createQuery("select l from Log l where l.message = :message", Log.class)
.setParameter("message", message)
.getResultList().stream().findAny();
}
}
- 중간에 예외 상황을 재현하기 위해 로그 예외라고 입력하는 경우 예외를 발생시킨다
MemberService
@Slf4j
@Service
@RequiredArgsConstructor
public class MemberService {
private final MemberRepository memberRepository;
private final LogRepository logRepository;
public void joinV1(String username){
Member member = new Member(username);
Log logMessage = new Log(username);
log.info("== memberRepository 호출 시작 ==");
memberRepository.save(member);
log.info("== memberRepository 호출 종료 ==");
log.info("== logRepository 호출 시작 ==");
logRepository.save(logMessage);
log.info("== logRepository 호출 종료 ==");
}
public void joinV2(String username){
Member member = new Member(username);
Log logMessage = new Log(username);
log.info("== memberRepository 호출 시작 ==");
memberRepository.save(member);
log.info("== memberRepository 호출 종료 ==");
log.info("== logRepository 호출 시작 ==");
try {
logRepository.save(logMessage);
}catch (RuntimeException e){
//로그 저장 실패시, 예외처리를 해준다.
log.info("log 저장에 실패했습니다. logMessage={}", logMessage.getMessage());
log.info("정상 흐름 반환");
}
log.info("== logRepository 호출 종료 ==");
}
}
- 회원을 등록하면서 동시에 회원 등록에 대한 DB 로그도 함께 남긴다.
- joinV1()
- 회원과 DB로그를 함께 남기는 비즈니스 로직이다.
- 현재 별도의 트랜잭션은 설정하지 않는다.
- joinV2()
- joinV1()과 같은 기능을 수행한다.
- DB 로그 저장 시 예외가 발생하면 예외를 복구한다.
- 현재 별도의 트랜잭션은 설정하지 않는다
MemberServiceTest
@Slf4j
@SpringBootTest
class MemberServiceTest {
@Autowired
MemberService memberService;
@Autowired
MemberRepository memberRepository;
@Autowired
LogRepository logRepository;
/**
* memberService @Transactional:OFF
* memberRepository @Transactional:ON
* logRepository @Transactional:ON
*/
@Test
public void outerTxOff_success() {
//given
String username = "outerTxOff_success";
//when
memberService.joinV1(username);
//then : 모든 데이터가 정상 저장된다.
assertTrue(memberRepository.find(username).isPresent());
assertTrue(logRepository.find(username).isPresent());
}
}728x90
'스프링 DB 2편(데이터 접근 활용 기술)' 카테고리의 다른 글
| Ch11. 스프링 트랜잭션 전파(활용) - 단일 트랜잭션 (0) | 2022.07.08 |
|---|---|
| Ch11. 스프링 트랜잭션 전파(활용) - 서비스 계층에 트랜잭션이 없을 때 (커밋, 롤백) (0) | 2022.07.08 |
| Ch10. 스프링 트랜잭션 전파(기본) - 다양한 전파 옵션 (0) | 2022.07.08 |
| Ch10. 스프링 트랜잭션 전파(기본) - REQUIRES_NEW (0) | 2022.07.07 |
| Ch10. 스프링 트랜잭션 전파(기본) - 내부 롤백 (0) | 2022.07.07 |