1. 개요
이 예제에서는 Spring Transactions를 구성하는 올바른 방법 , @Transactional 어노테이션 을 사용하는 방법 및 일반적인 함정에 대해 설명합니다.
핵심 지속성 구성에 대한 자세한 내용은 Spring with JPA 사용방법(예제)를 확인하세요 .
기본적으로 트랜잭션, 어노테이션 및 AOP를 구성하는 두 가지 고유한 방법이 있으며 각각 고유한 장점이 있습니다. 여기에서 보다 일반적인 어노테이션 구성에 대해 논의할 것입니다.
2. 트랜잭션 구성
Spring 3.1은 트랜잭션 지원을 활성화하기 위해 @Configuration 클래스에서 사용할 수 있는 @EnableTransactionManagement 어노테이션 을 도입합니다.
@Configuration
@EnableTransactionManagement
public class PersistenceJPAConfig{
@Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
//...
}
@Bean
public PlatformTransactionManager transactionManager() {
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(entityManagerFactory().getObject());
return transactionManager;
}
}
그러나 Spring Boot 프로젝트를 사용 중이고 클래스 경로에 spring-data-* 또는 spring-tx 의존성이 있는 경우 트랜잭션 관리가 기본적으로 활성화됩니다 .
3. XML로 트랜잭션 구성
3.1 이전 버전의 경우 또는 Java가 옵션이 아닌 경우 어노테이션 기반 및 네임스페이스 지원 을 사용하는 XML 구성은 다음 과 같습니다.
<bean id="txManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="myEmf" />
</bean>
<tx:annotation-driven transaction-manager="txManager" />
4. @Transactional 어노테이션
트랜잭션이 구성되면 이제 클래스 또는 메소드 수준에서 @Transactional 로 빈에 어노테이션을 달 수 있습니다 .
@Service
@Transactional
public class FooService {
//...
}
어노테이션은 추가 구성 도 지원합니다.
- 트랜잭션 의 전파 유형
- 트랜잭션 의 격리 수준
- 트랜잭션에 의해 래핑된 작업에 대한 시간 초과
- readOnly 플래그 – 트랜잭션이 읽기 전용이어야 한다는 지속성 제공자에 대한 힌트
- 트랜잭션에 대한 롤백 규칙
기본적으로 롤백은 확인되지 않은 예외에 대해서만 런타임에 발생합니다. 확인된 예외는 트랜잭션 롤백을 트리거하지 않습니다 . 물론 rollbackFor 및 noRollbackFor 어노테이션 매개변수 를 사용하여 이 동작을 구성할 수 있습니다 .
5. 잠재적 위험
5.1. 트랜잭션 및 프록시
높은 수준에서 Spring은 @Transactional 로 어노테이션이 달린 모든 클래스에 대한 프록시를 클래스 또는 메소드에 생성합니다. 프록시를 사용하면 프레임워크가 주로 트랜잭션 시작 및 커밋을 위해 실행 중인 메서드 전후에 트랜잭션 논리를 삽입할 수 있습니다.
명심해야 할 중요한 점은 트랜잭션 빈이 인터페이스를 구현하는 경우 기본적으로 프록시는 Java 동적 프록시가 된다는 것입니다. 즉, 프록시를 통해 들어오는 외부 메서드 호출만 가로채게 됩니다. 메서드에 @Transactional 어노테이션 이 있더라도 모든 자체 호출 호출은 트랜잭션을 시작하지 않습니다 .
프록시 사용에 대한 또 다른 주의 사항은 공용 메서드에만 @Transactional 어노테이션을 달아야 한다는 것입니다. 다른 가시성의 메서드는 프록시되지 않기 때문에 어노테이션을 자동으로 무시합니다.
5.2. 격리 수준 변경
courseDao.createWithRuntimeException(course);
트랜잭션 격리 수준을 변경할 수도 있습니다.
@Transactional(isolation = Isolation.SERIALIZABLE)
이것은 실제로 Spring 4.1에서 도입 되었다는 점에 유의하십시오. Spring 4.1 이전에 위의 예제를 실행하면 결과는 다음과 같습니다.
org.springframework.transaction.InvalidIsolationLevelException: Standard JPA does not support custom isolation levels – use a special JpaDialect for your JPA implementation
5.3. 읽기 전용 트랜잭션
readOnly 플래그 는 특히 JPA로 작업할 때 일반적으로 혼동을 일으킵니다. Javadoc에서:
This just serves as a hint for the actual transaction subsystem; it will not necessarily cause failure of write access attempts. A transaction manager which cannot interpret the read-only hint will not throw an exception when asked for a read-only transaction.
사실은 readOnly 플래그가 설정되어 있을 때 삽입 또는 업데이트가 발생하지 않을 것이라고 확신할 수 없다는 것 입니다. 이 동작은 공급업체에 따라 다르지만 JPA는 공급업체에 구애받지 않습니다.
readOnly 플래그는 트랜잭션 내에서만 관련이 있다는 점을 이해하는 것도 중요 합니다 . 작업이 트랜잭션 컨텍스트 외부에서 발생하면 플래그가 무시됩니다. 간단한 예는 다음과 같이 어노테이션이 달린 메서드를 호출합니다.
@Transactional(propagation = Propagation.SUPPORTS, readOnly = true)
비트랜잭션 컨텍스트에서 트랜잭션이 생성되지 않고 readOnly 플래그가 무시됩니다.
5.4. 트랜잭션 로깅
트랜잭션 관련 문제를 이해하는 데 유용한 방법은 트랜잭션 패키지의 로깅을 미세 조정하는 것입니다. Spring의 관련 패키지는 " org.springframework.transaction" 이며 로깅 수준이 TRACE 로 구성되어야 합니다 .
5.5. 트랜잭션 롤백
@Transactional 어노테이션은 메서드에서 트랜잭션의 의미를 지정하는 메타데이터입니다 . 트랜잭션을 롤백하는 방법에는 선언적 및 프로그래밍 방식의 두 가지가 있습니다.
선언적 접근 방식에서는 메서드에 @ Transactional 어노테이션 을 추가 합니다. @Transactional 어노테이션은 rollbackFor 또는 rollbackForClassName 속성을 사용 하여 트랜잭션을 롤백하고 noRollbackFor 또는 noRollbackForClassName 속성을 사용 하여 나열된 예외에서 롤백을 방지합니다.
선언적 접근 방식의 기본 롤백 동작은 런타임 예외에서 롤백합니다.
런타임 예외 또는 오류에 대한 트랜잭션을 롤백하기 위해 선언적 접근 방식을 사용하는 간단한 예를 살펴보겠습니다.
@Transactional
public void createCourseDeclarativeWithRuntimeException(Course course) {
courseDao.create(course);
throw new DataIntegrityViolationException("Throwing exception for demoing Rollback!!!");
}
다음으로 선언적 접근 방식을 사용하여 나열된 확인된 예외에 대한 트랜잭션을 롤백합니다. 이 예제 의 롤백 은 SQLException 에 있습니다 .
@Transactional(rollbackFor = { SQLException.class })
public void createCourseDeclarativeWithCheckedException(Course course) throws SQLException {
courseDao.create(course);
throw new SQLException("Throwing exception for demoing rollback");
}
나열된 예외에 대한 트랜잭션 롤백을 방지하기 위해 선언적 접근 방식에서 속성 noRollbackFor 의 간단한 사용을 살펴보겠습니다 .
@Transactional(noRollbackFor = { SQLException.class })
public void createCourseDeclarativeWithNoRollBack(Course course) throws SQLException {
courseDao.create(course);
throw new SQLException("Throwing exception for demoing rollback");
}
프로그래밍 방식 에서는 TransactionAspectSupport 를 사용하여 트랜잭션을 롤백합니다 .
public void createCourseDefaultRatingProgramatic(Course course) {
try {
courseDao.create(course);
} catch (Exception e) {
TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
}
}
6. 결론
이 기사에서는 Java와 XML을 모두 사용하여 트랜잭션 시맨틱의 기본 구성을 다루었습니다. 또한 @Transactional 을 사용하는 방법 과 트랜잭션 전략의 모범 사례 도 배웠습니다 .
항상 그렇듯이 이 기사에 제시된 코드는 Github에서 사용할 수 있습니다 .