Spring的事务管理

Spring的事务管理
文章目录

  • Spring的事务管理
    • 一、数据库事务
      • 1.1 数据库事务的四个特性(ACID)
      • 1.2 数据并发的问题
      • 1.3 数据库锁机制
      • 1.4 事务的隔离级别
      • 1.5 JDBC对事务的支持
    • 二、`ThreadLocal`
      • 2.1 与Thread同步机制的比较
    • 三、Spring对事务管理的支持
      • 3.1 事务管理关键抽象
      • 3.2 Spring的事务管理器实现类
    • 四、Spring的事务传播
    • 五、事务配置
      • 5.1 使用原始的`TransactionProxyFactoryBean`
        • (1) 声明式事务配置
        • (2) 基于aop/tx命名空间的配置
      • (3) 基于注解的声明式事务
    • 六、混合数据访问技术框架——Spring事务管理器的应对
      • Hibernate混合技术使用时的注意
    • 七、不能被实施Spring AOP事务的方法

一、数据库事务 1.1 数据库事务的四个特性(ACID)
  • 原子性(Atomic)
  • 一致性(一致性是最终目标)(consistency)
  • 隔离性(isolation)
  • 持久性(durability)
1.2 数据并发的问题
  • 脏读(A事务读取B事务尚未提交的更改数据)
  • 不可重复读(A事务读取了B事务已经提交的更改数据)
  • 幻象读(A事务读取了B事务提交的新增数据)
  • 第一类丢失更新(A事务撤销时,把已经提交的B事务的更新数据覆盖了)
  • 第二类丢失更新(A事务覆盖了B事务已经提交的数据,造成B事务所做的操作丢失)
1.3 数据库锁机制
数据库通过锁机制解决并发访问的问题。
按锁定的对象的不同:
  • 表锁定:对整张表进行锁定
  • 行锁定:对表中的特定行进行锁定
从并发事务锁定的关系上看
  • 共享锁定
  • 独占锁定
1.4 事务的隔离级别
数据库为用户提供了锁的DML操作方式,但直接使用锁管理是非常麻烦的,因此数据库为用户提供了自动锁机制。只要用户指定会话的事务隔离级别,数据库就会分析事务中的SQL语句,然后自动为事务操作的数据资源添加适合的锁。
  • read uncommited
  • read commited
  • repeatable read
  • serializable
隔离级别和并发性是对立的。
1.5 JDBC对事务的支持
  • 不是所有的数据库都支持事务
  • 支持事务的数据库并非支持所有的事务隔离级别
二、ThreadLocal ThreadLocal为每个使用该变量的线程分配一个独立的变量副本。
2.1 与Thread同步机制的比较
对于多线程资源共享的问题,同步机制采用“以时间换空间”的方式,访问串行化,对象共享化;而ThreadLocal采用了“以空间换时间”的方式,访问并行化,对象独享化。
三、Spring对事务管理的支持 3.1 事务管理关键抽象
Spring事务管理SPI(Service Provider Interface)的抽象层主要包含3个接口:PlatformTransactionManagerTransactionDefinitionTransactionStatus
  • TransactionDefinition: 定义Spring兼容的事务属性,事务隔离、事务传播、超时时间、只读状态
    只读事务不修改任何数据,资源事务管理者可以针对可读事务应用一些优化措施,提高运行性能。只读事务在某些情况下(如使用Hibernate时)是一种非常有用的优化,试图在只读事务中更改数据将引发异常。
  • TransactionStatus: 代表一个事务的具体运行状态
  • PlatformTransactionManager: 根据TransactionDefinition提供的事务属性配置信息创建事务,并用TransactionStatus描述这个激活事务的状态。
3.2 Spring的事务管理器实现类
Spring为不同的持久化框架提供了PlatformTransactionManager接口的实现类:
  • JpaTransactionManager
  • HibernateTransactionManager
  • DataSourceTransactionManager
  • JtaTransactionManager 具有多个数据源的全局事务使用该事务管理器(不管采用何种持久化技术)
四、Spring的事务传播 所谓事务传播行为,就是多个事务方法相互调用时,事务如何在这些方法间传播。注:事务方法可以嵌套调用。
【Spring的事务管理】除了事务的传播行为,对于事务的其他特性,Spring时借助底层资源的功能来完成的,Spring无非充当了一个代理的角色。但是事务的传播行为确实Spring凭借自身的框架提供的功能,是Spring提供给开发者最珍贵的礼物。
Spring在TransactionDefinition中规定了7种类型的事务传播行为:
  • PROPAGATION_REQUIRED 如果当前没有事务,则新建一个事务;如果已经存在一个事务,则加入到这个事务中,这是最常见的选择。
  • PROPAGATION_SUPPORTS 支持当前事务,如果当前没有事务,则以非事务方式执行;
  • PROPAGATION_MANDATORY 使用当前事务,如果当前没有事务,则抛出异常;
  • PROPAGATION_REQUIRES_NEW 新建事务,如果当前存在事务,则将当前事务挂起;
  • PROPAGATION_NOT_SUPPORTED 以非事务方式执行操作,如果当前存在事务,则把当前事务挂起;
  • PROPAGATION_NEVER 以非事务方式执行。如果当前存在事务,则抛出异常;
  • PROPAGATION_NESTED如果当前存在事务,则在嵌套事务内执行;如果当前没有事务,则执行与PROPAGATION_REQUIRED类似的操作。
Spring默认的事务传播行为是PROPAGATION_REQUIRED
在相同线程中进行相互嵌套调用的事务方法工作在相同的事务中。如果这些相互嵌套调用的方法工作在不同的线程中,则不同线程下的事务方法工作在独立的事务中。
五、事务配置 5.1 使用原始的TransactionProxyFactoryBean
(1) 声明式事务配置
  • 的配置规则: PROPAGATION(传播属性),ISOLATION(隔离级别),readOnly(是否为只读事务),-Exception(发生异常时回滚事务),+Exception(发生异常时照样提交事务)
  • 传播事务是唯一必须提供的配置项,当的值为空时,不会发生异常,但对应的配置方法不会应用事务,相当于没有配置
  • Spring默认的事务回滚规则为“运行期异常回滚,检查型异常不回滚”;
PROPAGATION_REQUIRED,readOnly PROPAGATION_REQUIRED

(2) 基于aop/tx命名空间的配置

(3) 基于注解的声明式事务

  • 注解本身具有一组普适性的默认事务属性,所以往往只要在事务管理的业务类中添加一个@Transactional注解,就完成了业务类食物属性的配置;
  • @Transactional的属性,可以配置:传播行为,隔离级别,读写属性,超时时间,回滚设置
  • Spring建议在具体的业务类上使用@Transaction注解;
    注解不能被继承
  • 在方法出的注解回覆盖类定义处的注解
  • 可以同时使用不同的事务管理器
@Transactional默认的属性:
  • 事务传播行为: PROPAGATION_REQUIRED
  • 事务隔离级别:ISOLATION_DEFAULT
  • 读写事务属性: 读写事务
  • 超时时间: 依赖底层的事务系统的默认值
  • 回滚设置: 任务运行期异常引发回滚,任何检查型异常不会引发回滚
六、混合数据访问技术框架——Spring事务管理器的应对 如果采用一种高端端ORM技术(Hibernate、JPA、JDO),同时还采用一种JDBC技术(Spring JDBC、MyBatis):由于前者的会话是对后者连接(Connection)对封装,Spring会“足够智能地“在同一个事务线程中让前者的会话封装后者的连接。所以只要直接采用前者的事务管理器就可以了。
事务隔离级别对并发问题的解决情况:
混合数据访问技术框架 事务管理器
Hibernate+Spring JDBC 或MyBatis org.springframework.orm.hibernateX.HibernateTransactionManager
JPA+Spring JDBC 或MyBatis org.springframework.orm.jpa.JpaTransactionManager
JDO+Spring JDBC 或MyBatis org.springframework.orm.jdo.JdoTransactionManager
Hibernate混合技术使用时的注意
在使用Hibernate时应当注意:
Hibernate对数据的更改只记录在一级缓存中,要等到事务提交或显式调用flush()方法时才会将一级缓存中的数据同步到数据库中。
使用Hibernate事务管理器后,可以混合使用Hibernate和Spring JDBC数据访问技术,它们将工作在同一事务上下文中。但是在使用Spring JDBC访问数据时,Hibernate的一级或二级缓存得不到同步。此外,一级缓存延迟数据同步机制可能会覆盖Spring JDBC数据更改的结果。
建议不要同时使用Spring JDBC和Hibernate对数据进行写操作。
七、不能被实施Spring AOP事务的方法 由于Spring事务管理时基于接口代理或动态字节码技术。
  • 可以实施接口动态代理的方法只能是使用public 或 public final修饰符的方法,其他方法不可能被动态代理,相应地就不能实施AOP增强,即不能进行Spring事务增强。
  • 基于CGLib字节码动态代理的方案是通过扩展被增强类,动态创建其子类的方法进行AOP增强植入的。由于使用final、static、private修饰符的方法都不能被子类覆盖,相应地这些方法将无法实施AOP增强。

    推荐阅读