Spring @Transactional 읽기 전용 전파
내 웹 레이어가 단일 트랜잭션 컨텍스트 내에서 Hibernate 엔터티와 함께 작동 할 수 있도록 명령 패턴을 사용하여 실험하고 있습니다 (따라서 지연로드 예외를 방지 함). 그러나 지금은 거래를 어떻게 처리해야하는지 혼란 스럽습니다.
내 명령은 주석이 달린 서비스 계층 메서드를 호출합니다 @Transactional
. 이러한 서비스 계층 방법 중 @Transactional(readOnly=true)
일부는 읽기 전용 이며 일부는 읽기 / 쓰기입니다.
내 서비스 계층은 웹 계층을 대신하여 전달 된 명령을 실행하는 명령 처리기를 노출합니다.
@Transactional
public Command handle( Command cmd ) throws CommandException
명령 처리기의 handle()
메서드를 트랜잭션으로 만드는 것이 옳다고 가정 합니다. 여기에서 혼란이 발생합니다. 명령 구현이 여러 서비스 계층 메서드를 호출하는 경우 명령 처리기가 명령 내에서 호출 된 작업이 읽기 전용인지, 읽기 / 쓰기인지 또는 조합인지 알 수있는 방법이 없습니다. 둘 중.
이 예제에서 전파가 어떻게 작동하는지 이해하지 못합니다. handle()
메서드 를 만드는 readOnly=true
경우 명령이 주석이 달린 서비스 계층 메서드를 호출하면 어떻게됩니까 @Transactional(realOnly=false)
?
이에 대해 더 잘 이해하고 의견을 보내 주시면 감사하겠습니다.
앤드류
우선 Spring은 지속성을 자체적으로 수행하지 않기 때문에 readOnly
정확히 무엇 을 의미 해야하는지 지정할 수 없습니다 . 이 속성은 공급자에 대한 힌트 일 뿐이며 동작은이 경우 Hibernate에 따라 다릅니다.
당신이 지정하는 경우 readOnly
로 true
, 플러시 모드로 설정됩니다 FlushMode.NEVER
트랜잭션을 커밋에서 세션을 방지 현재 최대 절전 모드 세션한다.
또한 setReadOnly (true) 는 JDBC 연결에서 호출되며 이는 기본 데이터베이스에 대한 힌트이기도합니다. 데이터베이스에서 지원하는 경우 (대부분 지원할 가능성이 높음) 기본적으로와 같은 효과가 FlushMode.NEVER
있지만 수동으로 플러시 할 수도 없기 때문에 더 강력합니다.
이제 트랜잭션 전파가 어떻게 작동하는지 살펴 보겠습니다.
당신이 명시 적으로 설정하지 않는 경우 readOnly
에 true
, 당신은 / 쓰기 트랜잭션을 읽을 것입니다. 트랜잭션 속성 (예 :)에 따라 REQUIRES_NEW
때때로 트랜잭션이 특정 지점에서 일시 중단되고 새 트랜잭션이 시작되고 최종적으로 커밋 된 후 첫 번째 트랜잭션이 재개됩니다.
좋아, 거의 다 왔어. readOnly
이 시나리오에 어떤 영향 이 있는지 살펴 보겠습니다 .
A의 방법 경우 읽기 / 쓰기 트랜잭션이 필요로하는 메소드를 호출 대한 읽기 전용 트랜잭션을, 첫 번째는 중단되어야한다 그렇지 않으면 플러시 때문에 / 두 번째 방법의 끝에 일어날 것 커밋합니다.
반대로 read / write 를 요구 하는 readOnly 트랜잭션 내에서 메서드를 호출하면 다시 플러시 / 커밋 될 수 없기 때문에 첫 번째 메서드가 일시 중단되고 두 번째 메서드는이를 필요로합니다.
년 에-readOnly 인 readOnly 인- 및 읽기 / 쓰기에-/ 쓰기 (당신은 분명, 그렇지 않으면 전파를 지정하지 않는) 경우 외부 트랜잭션을 중단 할 필요가 없습니다.
readOnly = true에서 readOnly = false를 호출하면 이전 트랜잭션이 계속되므로 작동하지 않습니다.
귀하의 예에서 서비스 계층의 handle () 메서드는 새로운 읽기-쓰기 트랜잭션을 시작합니다. 핸들 메서드가 읽기 전용으로 주석 처리 된 서비스 메서드를 차례로 호출하면 읽기 전용이 대신 기존 읽기-쓰기 트랜잭션에 참여하므로 효과가 없습니다.
이러한 메소드가 읽기 전용이어야하는 경우 Propagation.REQUIRES_NEW로 주석을 달 수 있으며 기존 읽기-쓰기 트랜잭션에 참여하지 않고 새 읽기 전용 트랜잭션을 시작합니다.
다음은 작동하는 예제입니다. CircuitStateRepository는 스프링 데이터 JPA 저장소입니다.
BeanS는 조회를 수행하는 transactional = read-only Bean1을 호출하고 새로운 객체를 저장하는 transactional = read-write Bean2를 호출합니다.
- Bean1은 읽기 전용 tx를 시작합니다.
31 09 : 39 : 44.199 [pool-1-thread-1] DEBUG osorm.jpa.JpaTransactionManager-이름이 [nz.co.vodafone.wcim.business.Bean1.startSomething] 인 새 트랜잭션 생성 : PROPAGATION_REQUIRED, ISOLATION_DEFAULT, readOnly; ''
Bean 2는 그것에 참여합니다.
31 09 : 39 : 44.230 [pool-1-thread-1] DEBUG osorm.jpa.JpaTransactionManager-기존 트랜잭션 참여
데이터베이스에는 아무것도 커밋되지 않습니다.
이제 @Transactional
추가 할 Bean2 주석을 변경 하십시오.propagation=Propagation.REQUIRES_NEW
Bean1은 읽기 전용 tx를 시작합니다.
31 09 : 31 : 36.418 [pool-1-thread-1] DEBUG osorm.jpa.JpaTransactionManager-이름이 [nz.co.vodafone.wcim.business.Bean1.startSomething] 인 새 트랜잭션 생성 : PROPAGATION_REQUIRED, ISOLATION_DEFAULT, readOnly; ''
Bean2는 새로운 읽기-쓰기 tx를 시작합니다.
31 09 : 31 : 36.449 [pool-1-thread-1] DEBUG osorm.jpa.JpaTransactionManager-현재 트랜잭션 일시 중지, [nz.co.vodafone.wcim.business.Bean2.createSomething] 이름으로 새 트랜잭션 생성
그리고 Bean2의 변경 사항은 이제 데이터베이스에 커밋됩니다.
다음은 spring-data, hibernate 및 oracle로 테스트 한 예제입니다.
@Named
public class BeanS {
@Inject
Bean1 bean1;
@Scheduled(fixedRate = 20000)
public void runSomething() {
bean1.startSomething();
}
}
@Named
@Transactional(readOnly = true)
public class Bean1 {
Logger log = LoggerFactory.getLogger(Bean1.class);
@Inject
private CircuitStateRepository csr;
@Inject
private Bean2 bean2;
public void startSomething() {
Iterable<CircuitState> s = csr.findAll();
CircuitState c = s.iterator().next();
log.info("GOT CIRCUIT {}", c.getCircuitId());
bean2.createSomething(c.getCircuitId());
}
}
@Named
@Transactional(readOnly = false)
public class Bean2 {
@Inject
CircuitStateRepository csr;
public void createSomething(String circuitId) {
CircuitState c = new CircuitState(circuitId + "-New-" + new DateTime().toString("hhmmss"), new DateTime());
csr.save(c);
}
}
기본적으로 트랜잭션 전파는 REQUIRED입니다. 즉, 동일한 트랜잭션이 트랜잭션 호출자에서 트랜잭션 호출 수신자로 전파됩니다. 이 경우에도 읽기 전용 상태가 전파됩니다. 예를 들어 읽기 전용 트랜잭션이 읽기-쓰기 트랜잭션을 호출하면 전체 트랜잭션이 읽기 전용이됩니다.
지연로드를 허용하기 위해 View에서 세션 열기 패턴을 사용할 수 있습니까? 이렇게하면 핸들 메서드가 트랜잭션 일 필요가 없습니다.
It seem to ignore the settings for the current active transaction, it only apply settings to a new transaction:
org.springframework.transaction.PlatformTransactionManager TransactionStatus getTransaction(TransactionDefinition definition) throws TransactionException Return a currently active transaction or create a new one, according to the specified propagation behavior. Note that parameters like isolation level or timeout will only be applied to new transactions, and thus be ignored when participating in active ones. Furthermore, not all transaction definition settings will be supported by every transaction manager: A proper transaction manager implementation should throw an exception when unsupported settings are encountered. An exception to the above rule is the read-only flag, which should be ignored if no explicit read-only mode is supported. Essentially, the read-only flag is just a hint for potential optimization.
ReferenceURL : https://stackoverflow.com/questions/1614139/spring-transactional-read-only-propagation
'developer tip' 카테고리의 다른 글
두 문자열의 유사성을 어떻게 측정 할 수 있습니까? (0) | 2021.01.07 |
---|---|
속성 이름을 기준으로 JavaScript 개체 정렬 (0) | 2021.01.07 |
jQuery에서 console.log는 무엇입니까? (0) | 2021.01.07 |
목록에서 모든 항목이 동일한 지 확인 (0) | 2021.01.07 |
git에서 빈 프로젝트에 분기 만들기 (0) | 2021.01.07 |