spring的事务管理

事务的ACID特性

原子性(Atomicity):一个事务必须被视为一个不可分割的最小工作单元,整个事务中的所有操作要么全部提交成功,要么全部失败回滚。

一致性(consistency):数据库总是从一个一致性的状态转换到另一个一致性的状态。在事务开始前后,数据库的完整性约束没有被破坏。例如违反了唯一性,必须撤销事务,返回初始状态。

隔离性(isolation):每个读写事务的对象对其他事务的操作对象能相互分离,即:事务提交前对其他事务是不可见的,通常内部加锁实现。

持久性(durability):一旦事务提交,则其所做的修改会永久保存到数据库。

spring中事务的属性

传播行为:

  1. PROPAGATION_REQUIRED
    支持当前事务;如果不存在,创建一个新的。这通常是事务定义的默认设置,通常定义事务同步作用域。
  2. PROPAGATION_SUPPORTS
    支持当前事务;如果不存在事务,则以非事务方式执行。
  3. PROPAGATION_REQUIRES_NEW
    创建一个新事务,如果存在当前事务,则挂起当前事务。
  4. PROPAGATION_MANDATORY
    支持当前事务;如果当前事务不存在,抛出异常。
  5. PROPAGATION_NEVER
    不支持当前事务;如果当前事务存在,抛出异常。
  6. PROPAGATION_NOT_SUPPORTED
    不支持当前事务,存在事务挂起当前事务;始终以非事务方式执行。
  7. PROPAGATION_NESTED
    如果当前事务存在,则在嵌套事务中执行,如果当前没有事务,类似PROPAGATION_REQUIRED(创建一个新的)。

注意:在当前事务存在的情况下PROPAGATION_REQUIRES_NEWPROPAGATION_NESTED有什么区别?
假如方法A调用方法B(下面都是在异常没有被捕获的情况下说的)
PROPAGATION_NESTED:这个是只要A没有抛异常,A都可以正常提交,B抛了异常,B自己回滚,A可以正常提交。但是如果A异常了,AB都会回滚。
PROPAGATION_REQUIRES_NEW:这个是只要B方法发生异常,AB都会回滚,如果只是A发生异常那么只有A回滚。

隔离级别
1.Read Uncommitted(读取未提交内容):可能读取其它事务未提交的数据。----脏读问题,不可重复读
2:Read Committed(读取提交内容):一个事务只能看见已经提交事务所做的改变。----不可重复读,幻读
3:Repeatable Read(可重读):同一事务内多次一致性非锁定读,取第一次读取时建立的快照版本(MVCC),保证了同一事务内部的可重复读。
4:Serializable(串行化):这是最高的隔离级别,它是在每个读的数据行上加上共享锁(LOCK IN SHARE MODE)。在这个级别,可能导致大量的超时现象和锁竞争。
.
不可重复读和幻读的区别:
  不可重复读:(读取数据本身的对比)一个事务在读取某些数据后的一段时间后,再次读取这个数据,发现其读取出来的数据内容已经发生了改变,就是不可重复读。
  幻读:(读取结果集条数的对比)一个事务按相同的查询条件查询之前检索过的数据,确发现检索出来的结果集条数变多或者减少(由其他事务插入、删除的),类似产生幻觉。

回滚机制(rollbackfor)

是否只读(readonly)

超时时间(timeout)

spring中事务失效的场景

1:数据库层面,数据库的引擎本身不支持事务
2:被@Transactional注解的方法所在的类没有被spring管理
3:被@Transactional注解的方法所在的类不是public的
4:自身调用的时候,调该类自己的方法,而没有经过 Spring 的代理类,默认只有在外部调用事务才会生效。因为被spring管理的时候spring内部aop创建的代理对象会把事务的自动提交机制关闭,然后开启事务。
5:如果修饰的方法是静态方法的话也会失效,因为spring底层使用反射创建代理对象,无论是spring默认的动态代理jdk,还是使用cglib都是没有办法创建代理对象的,代理对象方法不生效,因为静态的方法是属于类的。(复习一下:jdk的动态代理要实现接口,通过创建接口实现类实现动态代理,cglib使用的是创建子类的方式实现动态代理,不要求类实现某个接口。)

@Service
public class OrderServiceImpl implements OrderService {

@Transactional
public void update(Order order) {
    updateOrder(order);
}

@Transactional(propagation = Propagation.REQUIRES_NEW)
public void updateOrder(Order order) {
    // update order
 }    
}

5:数据源没有配置事务管理器
6:没有配置回滚的异常类型,默认是RuntimeException,发生的异常不属于这个类。

还有一个问题,被final修饰的方法可以被代理吗?如果使用cglig的代理方式的话肯定是不行的,因为cglib是基于创建子类的方式实现的,那jdk的动态代理是基于接口的,这样按理说应该是可以被代理的吧,下面我们做实验进行验证以下。

final修饰的方法,如果没有实现接口的话,注入的时候会是null,所以会失败。报错。
在这里插入图片描述
final修饰的方法如果实现了接口也是可以进行代理的。不过这个时候要指定使用jdk的动态代理,在配置文件中指定spring.aop.proxy-target-class=false
在这里插入图片描述

这里我测试了一下,如果把报异常的代码注释打开,在指定使用jdk动态代理的情况下,如果这个类实现了接口也是可以实现回滚的,说明代理类创建成功了。如果不指定使用jdk的动态代理的话还是导致bean是null。
在这里插入图片描述

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

北海冥鱼未眠

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值