학습하는 분들께 도움이 되고, 더 좋은 답변을 드릴 수 있도록 질문전에 다음을 꼭 확인해주세요. 1. 강의 내용과 관련된 질문을 남겨주세요. 2. 인프런의 질문 게시판과 자주 하는 질문(링크)을 먼저 확인해주세요. (자주 하는 질문 링크: https://bit.ly/3fX6ygx) 3. 질문 잘하기 메뉴얼(링크)을 먼저 읽어주세요. (질문 잘하기 메뉴얼 링크: https://bit.ly/2UfeqCG) 질문 시에는 위 내용은 삭제하고 다음 내용을 남겨주세요. ========================================= [질문 템플릿] 1. 강의 내용과 관련된 질문인가요? (예/아니오) 예 2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예/아니오) 예 3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/아니오) 예 [질문 내용] 안녕하세요 영한님 이번에 트랜잭션 적용하면서 @Transactional(readOnly = true) 가 붙은 조회 메서드 내부에 @Transactional(propagation = Propagation.REQUIRES_NEW) 가 붙은 외부 클래스의 메서드가 사용 될 때 물리 트랜잭션이 분리되었고 각각 다른 트랜잭션임에도 변경감지가 적용안되는 부분이 궁금했습니다. 아래는 궁금한 부분에 대한 테스트를 진행한 코드입니다. @Service @RequiredArgsConstructor public class TeamService { private final TeamRepository teamRepository; private final TeamExternalService externalService; @Transactional(readOnly = true) public Team findTeamWithNameChangeExternal(Team team, String name) { Team findTeam = teamRepository.findByName(team.getName()); externalService.changeName(findTeam, name); return findTeam; } } @Service @RequiredArgsConstructor public class TeamExternalService { @Transactional(propagation = Propagation.REQUIRES_NEW) public void changeName(Team findTeam, String name) { findTeam.setName(name); } } @Test void findTeamWithNameChangeExternal() { Team team = new Team("team"); Team savedTeam = teamRepository.save(team); teamService.findTeamWithNameChangeExternal(savedTeam, "changeName"); Team findTeam = teamRepository.findByName("changeName"); assertThat(findTeam.getName()).isEqualTo("changeName"); } 같은 클래스에서 내부 호출 할 경우에는 REQUIRES_NEW 를 적용하더라도 같은 프록시 객체로 해당 메서드가 호출된 상위 트랜잭션의 옵션을 그대로 따라 가기 때문에 변경 감지가 적용안된다고 생각했어요 하지만 이와 다른 외부 클래스의 분리된 트랜잭션에서는 변경 감지가 일어나는 것이 정상이라고 생각했는데 왜 변경 감지가 일어나지 않는 것일 까요 ..? 아래는 궁금해서 디버그를 찍어봤어요 보니가 두 트랜잭션의 번호가 Transaction@13592로 같고 REQUIRES_NEW 가 적용된 트랜잭션의 경우에는 oldTrasactionInfo 이라는 정보를 갖고 해당 메서드를 실행하는 @Transactional(readOnly = true) 옵션이 적혀있더라구요 ?? 그렇다면 내부 호출이 아닌 외부 호출이라도 readOnly = true 로 조회 성능을 챙기면서 변경 감지를 사용할 순 없는 것인가요 ??
@tranactional 이 붙은 메소드 안에서 외부 서비스 api를 call 해야하는 상황이 있는데 컨트롤러 단에서 로직 분리가 힘든 상황입니다. @tranactional 이 붙은 메소드 안에서 아래와 같이 TransactionSynchronizationManager를 선언하고 override한 aftercommit 내부에서 호출하게 될 경우 마찬가지로 외부 서비스 api에 장애가 발생했을 때도 본 서비스에 장애로 이어질 수 있을까요?? TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronizationAdapter() { @Override public void afterCommit() { // 여기서 외부서비스 api 호출 } });
[질문 템플릿] 1. 강의 내용과 관련된 질문인가요? 예 2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? 예 3. 질문 잘하기 메뉴얼을 읽어보셨나요? 예 역시 백문이 불여일타!! 강의 보고 혼자 샘플작성하다 막 터집니다. 강의 볼때는 '음~ 그렇지~' 하고 보던게 안보고 혼자 작성해보니 강사님이 말씀하시는 "이거 분명이 개발할 때 문제 발생합니다." 하는거 다 터지네요. [질문 내용] InitDB.java 샘플 따라하다가 궁금한점이 생겨 질문 드립니다. 애플리케이션 구동 시 초기 데이터를 넣기 위해 @PostConstruct 로 코드를 작성하는 부분에서 문제가 발생했습니다. "Caused by: javax.persistence.TransactionRequiredException: No EntityManager with actual transaction available for current thread - cannot reliably process 'persist' call" 결론은 영속성 관리가 안되는 문제인거 같습니다. 근데 @Transactional을 붙였고 내부 함수 호출도 아닌데 왜 관리가 안되냐해서 디버깅을 해봤습니다. PostConstruct 하는 부분을 따라가 보니 해당 함수를 invoke하는 클래스가 프록시가 아니더군요. InitDB의 내부 맴버는 프록시인데. 질문: PostConstruct를 호출되는 대상 클래스도 spring container에 있는 bean같은데 왜 저넘은 프록시가 아닌거죠? 다른 bean의 맴버로 주입되는 bean만 프록시인 건가요?
안녕하세요 영한님 JPA 수업을 정말 잘듣고 있으며 이 수업을 듣고 제가 실무에서 적용을 하면서 인정받고 있어서 정말 감사합니다. 실무를 하던 중 문제는 해결하였으나 원리가 잘 이해가 안가는 부분이 있는데 구글리을 해도 좀처럼 나오지 않아 이렇게 질문을 드립니다 문제가 되는 코드는 실무코드라 간추린 버전으로 올리겠습니다. 추상클래스 입니다. method1()은 구현을 했으며 method2()는 추상메소드입니다 구현클래스이고 추상 메소드인 method2만 오버라이딩하여 구현했습니다 이상황에서 ExampleClass ex = new ExampleClass(); ex.method1(); 이렇게 실행했을 때 저는 생각한 것이 - ExampleClass는 상속을 받았으므로 method1()이 있다. - ExampleClass에 @transactional을 걸었으므로 method1()에도 @transactional이 걸릴 것이다 그런데 막상 실행해보니 트랜잭션이 실행되지 않더군요 그래서 여러가지시도를 한 결과 부모클래스인 AbstractExampleClass에 @transactional을 걸으니 해결되었었습니다. 그런데 문제는 해결했으나 원리가 잘 이해가 되지 않습니다. - ex.method1()를 실행하면 ExampleClass에 @transactional이 있으므로 AOP에서 트랜잭션을 실행해주는 것이 아닌가? 이런 생각이 들더군요 아마 제가 @transactional과 AOP의 자세한 구동원리를 잘 몰라서 그런거 같은데 왜 ExampleClass에 @transactional을 붙이면 안되고 추상클래스에 붙여야 하는지 원리를 자세히 알 수 있을까요?