Spring 之 声明式事务控制

本文深入解析Spring框架中事务管理的配置方法,包括注解配置和XML配置两种方式,详细介绍了事务管理器的实现,如DataSourceTransactionManager、JtaTransactionManager和HibernateTransactionManager,以及事务的传播行为、隔离级别、回滚策略、只读属性和超时时间的配置。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

注解配置

(1)
不管是注解配置方式,还是 XML 配置方式,都需要在配置文件中配置事务管理器。

事务管理器的主要实现有:

  • DataSourceTransactionManager:在应用程序中只需要处理一个数据源,而且通过 JDBC 存取。
  • JtaTransactionManager:在 JavaEE 应用服务器上用 JTA(Java Transaction API) 进行事务管理。
  • HibernateTransactionManager:用 Hibernate 框架存取数据库。
<!-- 1. 配置事务管理器 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="dataSource"></property>
</bean>

(2)
在对应的方法上加上 @Transactional 注解。在 @Transactional 注解中还可以配置事务的属性,比如事务的传播行为、事务的隔离级别、是否只读、超时时间等。

  1. 事务的传播行为
    @Transactional 注解的 propagation 属性中定义。
    事务的传播行为指的是:当一个事务方法被另一个事务方法调用的时候,是用另一个方法的事务,还是将另一个方法的事务挂起,自己新开一个事务呢?

    Spring 定义了 7 种传播行为:
    在这里插入图片描述
    最常用的是 REQUIREDREQUIRED_NEW,默认的传播行为时 REQUIRED
    ① REQUIRED
    当一个事务方法被另一个事务方法调用的时候,这种情况是使用另一个方法的事务。在这里插入图片描述
    ② REQUIRED_NEW
    这种情况是将另一个方法的事务挂起,而开启一个新事务,并在自己的事务内运行。在这里插入图片描述
    这两种情况具体的区别就是:比如我们在双十一的时候要抢购东西,我们事先将这些商品加入到购物车中,但是在 0 点支付的时候,银行卡中的钱不够了,这时候事务的传播行为如果是 REQUIRED,则一件商品也买不到,而如果是 REQUIRED_NEW 的话,则会买到一部分商品。

  2. 事务的隔离级别
    @Transactional 注解的 isolation 属性中定义。
    MySQL 中有 4 中隔离级别,分别是:READ_UNCOMMITTED、READ_COMMITTED、REPEATABLE_READ、SERIALIZABLE。

  3. 哪些异常回滚,哪些异常不回滚
    rollbackFor 属性中指定遇到时必须进行回滚的异常类型,可以为多个;
    noRollbackFor 属性中指定遇到时不回滚的异常类型,可以为多个。
    默认情况下捕获到 RuntimeException 或 Error 时回滚,而捕获到编译时异常不回滚。

  4. 事务是否只读
    如果一个事物只读取数据但不做修改,数据库引擎可以对这个事务进行优化。
    所以我们可以在 readOnly 属性中配置该事务是否是只读事务,从而帮助数据库引擎优化事务。

  5. 事务的超时时长
    如果一个事务长时间占用资源,则会使整体的性能下降。
    我们可以配置 timeout 的属性,用来指明当一个事务的运行时长超过我们配置的超时时长就会强制回滚,超时时长以秒为单位。

下面来看一个示例:

/**
  * 添加事务注解
  * 1.使用 propagation 指定事务的传播行为, 即当前的事务方法被另外一个事务方法调用时,如何使用事务, 默认取值为 REQUIRED, 即使用调用方法的事务
      REQUIRES_NEW: 事务自己的事务, 调用的事务方法的事务被挂起. 
  * 2.使用 isolation 指定事务的隔离级别, 最常用的取值为 READ_COMMITTED
  * 3.默认情况下 Spring 的声明式事务对所有的运行时异常进行回滚. 也可以通过对应的属性进行设置. 通常情况下取默认值即可. 
  * 4.使用 readOnly 指定事务是否为只读. 表示这个事务只读取数据但不更新数据, 这样可以帮助数据库引擎优化事务. 若真的是一个只读取数据库值的方法, 应设置 readOnly=true
  * 5.使用 timeout 指定强制回滚之前事务可以占用的时间.  
  */
@Transactional(propagation=Propagation.REQUIRES_NEW,
                            isolation=Isolation.READ_COMMITTED,
                            noRollbackFor={UserAccountException.class},
                            readOnly=false,
                            timeout=3)
@Override
public void purchase(String username, String isbn) {
    //1. 获取书的单价
    int price = bookShopDao.findBookPriceByIsbn(isbn);

    //2. 更新数的库存
    bookShopDao.updateBookStock(isbn);

    //3. 更新用户余额
    bookShopDao.updateUserAccount(username, price);
}

(3)
配置了 @Transactional 注解之后,如何让该注解起作用呢?
我们还需要在配置文件中开启事务注解支持:

<!-- 启用事务注解 -->
<tx:annotation-driven transaction-manager="transactionManager"/>

前提是在配置文件中加入 tx 命名空间。

XML 配置

当然我们也可以采用 XML配置的方式,也需要 3 个步骤:
(1)配置事务管理器

<!-- 1. 配置事务管理器 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="dataSource"></property>
</bean>

(2)配置事务的属性

<!-- 2. 配置事务属性 -->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
    <tx:attributes>
        <!-- 根据方法名指定事务的属性,如果没有配置属性则表示采用默认的属性 -->
        <tx:method name="purchase" propagation="REQUIRES_NEW" isolation="READ_COMMITTED" no-rollback-for="java.lang.ArithmeticException,java.lang.NullPointerException" read-only="false" timeout="5"/>
        <tx:method name="get*" read-only="true"/>
        <tx:method name="find*" read-only="true"/>
        <tx:method name="*"/>
    </tx:attributes>
</tx:advice>

(3)配置切入点表达式,表示事务应用在哪些方法上,并将切入点表达式和事务属性关联起来

<!-- 3. 配置事务切入点,,以及把事务切入点和事务属性关联起来 -->
<aop:config>
    <aop:pointcut id="txPointCut" expression="execution(* com.spring.tx.xml.service.*.*(..))" />
    <aop:advisor advice-ref="txAdvice" pointcut-ref="txPointCut"/>	
</aop:config>
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值