使用Spring 4和JPA进行事务配置


1.概述

本教程将讨论配置Spring Transactions的正确方法,如何使用@Transactional注释和常见陷阱。

有关核心持久性配置的更深入讨论,请查看Spring with JPA教程。

有两种不同的方式来配置事务 - 注释和AOP - 每种都有自己的优势 - 我们将在这里讨论更常见的注释配置。

2.配置不带XML的事务

Spring 3.1引入了@EnableTransactionManagement注释,用于@Configuration类并启用事务支持:

@Configuration
@EnableTransactionManagement
public class PersistenceJPAConfig{

   @Bean
   public LocalContainerEntityManagerFactoryBean
     entityManagerFactoryBean(){
      //...
   }

   @Bean
   public PlatformTransactionManager transactionManager(){
      JpaTransactionManager transactionManager
        = new JpaTransactionManager();
      transactionManager.setEntityManagerFactory(
        entityManagerFactoryBean().getObject() );
      return transactionManager;
   }
}

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 Annotation

配置事务后,现在可以在类或方法级别使用@Transactional注释bean:

@Service
@Transactional
public class FooService {
    //...
}

注释还支持进一步配置:

交易的传播类型 交易的隔离级别 由事务包装的操作的超时 一个readOnly的标志 -为持久性提供一个暗示,该交易应为只读 事务的回滚规则 请注意 - 默认情况下,仅对运行时进行回滚,仅对未经检查的异常进行回滚。已检查的异常不会触发事务的回滚 ; 当然,可以使用rollbackFor和noRollbackFor注释参数配置行为。

5.潜在的陷阱

5.1。交易和代理

在较高的层次上,Spring为所有使用@Transactional注释的类创建代理 - 无论是在类还是在任何方法上。代理允许框架在调用方法之前和之后注入事务逻辑 - 主要用于启动和提交事务。

需要记住的重要一点是,如果事务bean正在实现接口,则默认情况下代理将是Java动态代理。这意味着只有通过代理进入的外部方法调用才会被截获 - 任何自调用调用都不会启动任何事务 - 即使该方法是使用@Transactional注释的。

使用代理的另一个警告是,只有公共方法应该使用@Transactional注释 - 任何其他可见性的方法将默默地忽略注释,因为这些注释不被代理。

本文将在此详细讨论进一步的代理陷阱。

5.2。更改隔离级别

您可以更改事务隔离级别 - 如下所示:

@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的日志记录级别进行配置。