kim.zhang

风在前,无惧!


  • 首页

  • 标签42

  • 分类12

  • 归档94

  • 搜索

声明性事务.md

发表于 2020-09-05 更新于 2021-11-21 分类于 Spring
本文字数: 5.4k 阅读时长 ≈ 5 分钟

声明性事务的使用步骤

1.声明性事务需要spring-tx的包。它依赖于AOP,还需要导入AOP相关的包。

1
2
org.springframework.spring-tx
....

2.配置事务管理器,事务管理器需要dataSource。开启事务,需要aop和tx名称空间。

1
2
3
4
5
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>

<tx:annotation-driven transaction-manager="transactionManager"/>

3.在需要事务控制的方法上添加@Transactional注解。

事务的属性

  • timeout:超时设置,时间单位为秒。当事务执行时间>timeout,事务还未执行结束,会抛出超时异常,避免长事务的产生。需要注意的一点是,如果有多个事务,需要把timeout设置在大事务上才有作用。如下所示,timeout属性应该设置在事务A这个大事务才生效。

  • 1
    2
    3
    4
    5
    6
    7
    @Transactional(propagation = Propagation.REQUIRED,timeout = 3)
    public void A(){
    // B事务,REQUIRES_NEW
    B();
    // C事务,REQUIRES_NEW
    C();
    }
  • readOnly:设置事务为只读事务,当数据库操作只有读操作时,可以设置为true,提高效率。

  • noRollbackFor:默认发生运行时异常和Error事务会回滚。可以通过noRollbackFor指定哪些运行时异常不回滚。参数是一个class数组。

  • 1
    @Transactional(noRollbackFor = {NullPointerException.class})
  • noRollbackForClassName:与noRollbackFor的区别在于通过类名指定哪些运行时异常不回滚。参数是一个string数组。

  • 1
    @Transactional(noRollbackForClassName = {"NullPointerException.class"})
  • rollBackFor:指定哪些checked异常可以回滚

  • noRollbackForClassName:通过类名指定哪些checked异常可以回滚

  • isolation:指定事务隔离级别

  • 1
    @Transactional(isolation = Isolation.REPEATABLE_READ)

事务传播行为

当涉及到多个事务时,事务传播行为就是规定事务间的多个关系的。常用的有REQUIRED(同一辆车,翻车一起翻)、REQUIRES_NEW(自己开一辆车,别人翻车,与我物无关)。

  • REQUIRED:如果存在一个事务,则支持当前事务。如果没有事务则开启一个新的事务。
  • REQUIRES_NEW:如果存在一个事务,则将当前事务挂起,重新开启一个新的事务。

下面举几个栗子说明:

栗子1:同是REQUIRED

大事务addOrder包含了两个小事务,传播行为都是REQUIRED。三个事务都是在同一辆车上,如果任何一个翻车了,三个事务全部回滚。如下,大事务抛出了运行时异常,insert()和update()方法都会回滚。

1
2
3
4
5
6
7
8
@Transactional
public void addOrder() {
// insert REQUIRED
productService.insert();
// update REQUIRED
orderService.update();
int a = 2 / 0;
}

栗子2:REQUIRED中包含REQUIRES_NEW,子事务不发生异常

大事务addOrder()中包含两个小事务。addOrder()和update()事务在同一辆车上,insert()自己开了一辆车。现在addOrder()发生了运行时异常,翻车了。addOrder()和update()事务在同一辆车上,都会回滚操作。但是insert()自己开的车不受影响,会插入成功。

1
2
3
4
5
6
7
8
@Transactional
public void addOrder() {
// insert REQUIRES_NEW
productService.insert();
// update REQUIRED
orderService.update();
int a = 2 / 0;
}

栗子3:REQUIRED中包含REQUIRES_NEW,子事务发生异常

大事务addOrder()中包含两个小事务。addOrder()和update()事务在同一辆车上,insert()自己开了一辆车。现在insert()发生了运行时异常,翻车了。按理说,insert()自己翻车,并不影响addOrder()和update()这辆车,也就是update会执行成功。但结果是insert()和update()都回滚了,原因在于insert发生了异常,异常往上抛出,到了addOrder,addOrder()也发生了运行时异常,导致update()回滚。

1
2
3
4
5
6
7
@Transactional
public void addOrder() {
// insert REQUIRES_NEW insert发生异常
productService.insert();
// update REQUIRED
orderService.update();
}

如果,子事务insert()不往上抛出异常,而是子事务内try..catch..,运行结果又是怎样的呢?

insert()和update()都执行成功了。因为insert()自己捕获了运行时异常,insert()的事务不回滚。同时也不会将异常向上抛出,update()也会执行成功。

栗子4:同是REQUIRES_NEW,子事务不发生异常

大事务addOrder()启动时创建一个事务,两个子事务也是自身启动一个事务,与大事务互不影响。大事务翻车,子事务不受影响,insert()和update()都执行成功。

1
2
3
4
5
6
7
8
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void addOrder() {
// insert REQUIRES_NEW
productService.insert();
// update REQUIRED
orderService.update();
int a = 2 / 0;
}

如果,insert()发生异常,异常往上抛,addOrder也发生了运行时异常。insert()会回滚,而update()都没机会执行,因为还没执行到update(),addOrder就回滚了。

栗子5:同是REQUIRES_NEW,子事务发生异常

如果,insert()发生异常,异常往上抛,addOrder也发生了运行时异常。insert()会回滚,而update()都没机会执行,因为还没执行到update(),addOrder就回滚了。

1
2
3
4
5
6
7
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void addOrder() {
// insert REQUIRES_NEW insert()发生异常
productService.insert();
// update REQUIRED
orderService.update();
}

如果,update()发生异常,异常会往上抛。addOrder也发生了运行时异常。update()肯定会回滚,而insert()方法不会回滚,因为insert()是自己开的一辆车,它会执行成功。

1
2
3
4
5
6
7
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void addOrder() {
// insert REQUIRES_NEW
productService.insert();
// update REQUIRED update()发生异常
orderService.update();
}

但是如果insert()是REQUIRED的传播行为,受到addOrder运行时异常的影响,insert()也会回滚? 实际上,这里会发生死锁,insert()与addOrder是同一个事务,插入数据之后,addOrder事务还没有提交,未释放锁,此时update()去更新需要获取到锁,就发生了死锁。

总结:不管哪一个事务发生了异常,在往上抛的时候,只要是REQUIRES_NEW的事务都会执行成功(不会回滚)

本类事务方法方法之间的调用是同一个事务

addOrder大事务中包含了insert()和update()两个子事务,两个子事务都是REQUIRES_NEW。按理说,addOrder事务发生运行时异常,并不会影响到insert()和update()两个子事务,insert()和update()应该执行成功。

但是,由于这是在本类方法中,都是使用的同一个代理对象,实际上是同一个事务…

只要有一个方法发生了异常,事务都会回滚。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
@Transactional(propagation = Propagation.REQUIRED)
public void addOrder() {
this.insert();
this.update();
int a = 2 / 0;
}

@Transactional(propagation = Propagation.REQUIRES_NEW)
public void insert() {
orderDao.insert();
}

@Transactional(propagation = Propagation.REQUIRES_NEW)
public void update() {
productDao.update();

}

xml配置事务

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>

<!--配置事务管理器,事务相关的属性,相当于注解的值-->
<tx:advice id="myAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="addOrder" propagation="REQUIRED" />
<tx:method name="insert" propagation="REQUIRES_NEW"/>
<tx:method name="update" propagation="REQUIRES_NEW"/>
</tx:attributes>
</tx:advice>


<aop:config>
<!-- 配置切入点,相当于要在哪个方法上标明@Transactional-->
<aop:pointcut id="pointCut" expression="execution(* com.imooc.service.impl3.OrderServiceImpl.*(..))"/>
<!-- 关联事务管理器的属性 -->
<aop:advisor advice-ref="myAdvice" pointcut-ref="pointCut" />
</aop:config>

一般情况下,使用xml配置事务管理器时,可以使用*来切入pointCut下的所有方法,而只读方法可以设置readOnly=true来提高性能。

1
2
3
4
5
6
<tx:attributes>
<tx:method name="get*" propagation="REQUIRED" read-only="true"/>
<tx:method name="search*" propagation="REQUIRED" read-only="true"/>
<tx:method name="find*" propagation="REQUIRED" read-only="true"/>
<tx:method name="*" propagation="REQUIRED"/>
</tx:attributes>
一毛也是爱~
Kim.Zhang 微信支付

微信支付

# 事务
Spring AOP.md
Spring容器.md
  • 文章目录
  • 站点概览
Kim.Zhang

Kim.Zhang

且行且珍惜
94 日志
12 分类
42 标签
E-Mail Weibo
  1. 1. 声明性事务的使用步骤
  2. 2. 事务的属性
  3. 3. 事务传播行为
    1. 3.1. 栗子1:同是REQUIRED
    2. 3.2. 栗子2:REQUIRED中包含REQUIRES_NEW,子事务不发生异常
    3. 3.3. 栗子3:REQUIRED中包含REQUIRES_NEW,子事务发生异常
    4. 3.4. 栗子4:同是REQUIRES_NEW,子事务不发生异常
    5. 3.5. 栗子5:同是REQUIRES_NEW,子事务发生异常
  4. 4. 本类事务方法方法之间的调用是同一个事务
  5. 5. xml配置事务
粵ICP备19091267号 © 2019 – 2022 Kim.Zhang | 629k | 9:32
本站总访问量 4 次 | 有 309 人看我的博客啦 |
博客全站共176.7k字
载入天数...载入时分秒...
0%