Spring事务,隔离性,传播性记录分析

目的:当一个方法内,有操作多张关联表数据的操作时,为保证数据的一致性,需要对这个方法开启事务。

  • 当方法内有异常时,则会进行回滚,数据返回到事务操作前;spring事务的数据回滚依赖于数据库对事务的支持

事务特性:

  • A -原子性 :事务内的数据修改操作要么都成功,要么都失败
  • C -一致性 :事务内相关联数据的一致性
  • I - 隔离型 :事务与事务之间的数据相互隔离互不影响
  • D -持久性 : 事务正常结束对表数据的修改是持久的

事务间的数据隔离级别 :(级别由低->高)

  • READ_UNCOMMITTED读未提交,在事务未commit提交前,其它事务可以读取改事务数据
  • READ_COMMITTED读提交,在事务commit 提交后,其它事务才可以读取改事务数据
  • REPEATABLE_READ可重复读取提交,第一次进入事务时的查询的值,会一直保存,其它事务提交数据不影响当前事务,该事务读取的值还是之前的。
  • SERIALIZABLE串行化,在其它事务开启时,select会加锁,在其它事务执行查询时会阻塞等待,前一个事务提交完成

脏读

  • 一个事务读取到了另一个事务未提交的数据操作结果

不可重复读

  • 一个事务对同一行数据重复读取两次,但是却得到了不同的结果;在读取期间,其它事务提交事务修改了值

幻读

  • 某个事务读取某范围内的数据时,另一个事务在这个范围内添加了新的记录会产生换行,如本来两条数据读出了3条;不满足可重复读。(默认 MVCC版本并发控制,会解决幻读,读已提交、可重复读是会在每行数据添加版本,提交时会比较版本号)
    隔离级别越高,越能保证数据的完整性和一致性,但是对并发性能的影响也越大
  • mysql默认隔离级别:REPEATABLE_READ
  • oracle默认隔离级别:READ_COMMITTED

在Spring中使用事务:

编程式事务实现(细粒度

	@Resource
    private TransactionTemplate transactionTemplate;

    @Override
    public void one() {
        //隔离级别、传播性设置
        //transactionTemplate.setIsolationLevel(TransactionDefinition.ISOLATION_REPEATABLE_READ);
        //transactionTemplate.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
        transactionTemplate.execute(status -> {
            test1Mapper.updateByPrimaryKey(new Test1().setId(1).setStatus("1"));
            int i=1/0;
            test2Mapper.updateByPrimaryKey(new Test2().setId(1).setStatus("1"));
            return true;
        });
    }

声明式事务实现 (粗粒度-方法级别)

	@Override
    @Transactional(rollbackFor = Throwable.class)
    public void two() {
        test1Mapper.updateByPrimaryKey(new Test1().setId(1).setStatus("1"));
        int i=1/0;
        test2Mapper.updateByPrimaryKey(new Test2().setId(1).setStatus("1"));
    }

Spring事务传播性

  • 事务传播是指,一个事务方法开启事务而这个方法内嵌了另一个事务方法时,事务与事务之间的传播关系

默认:Propagation.REQUIRED ,表示当前方法必须运行在事务中,如果没有则新建一个事务

案例一 :contain() 方法开启事务,内嵌方法 updateT3AndT4() 未开启事务,此时都会算在一个事务内,报错一起回滚,单独调用updateT3AndT4()不存在事务。

    @Override
    @Transactional(rollbackFor = Throwable.class)
    public void contain() {
        test1Mapper.updateByPrimaryKey(new Test1().setId(1).setStatus("1"));
        test2Mapper.updateByPrimaryKey(new Test2().setId(1).setStatus("1"));
        test2Service.updateT3AndT4();
    }


	@Override
	//@Transactional(rollbackFor = Throwable.class) 效果一样
    public void updateT3AndT4() {
        test3Mapper.updateByPrimaryKey(new Test3().setId(1).setStatus("1"));
        int i=1/0;
        test4Mapper.updateByPrimaryKey(new Test4().setId(1).setStatus("1"));
    }

默认:Propagation.SUPPORTS ,表示当前不需要事务上下文,如果存在当前事务,那么该方法会在事务中运行

案例二:当前外层方法不是 propagation = Propagation.REQUIRED 级别时,因为如果是这级别,那里外都会在一个事务中,都会生效异常回滚。

	@Override
    @Transactional(rollbackFor = Throwable.class,propagation = Propagation.SUPPORTS)
    public void contain() {
        test1Mapper.updateByPrimaryKeySelective(new Test1().setId(1).setStatus("1"));
        int i=1/0;
        test2Mapper.updateByPrimaryKeySelective(new Test2().setId(1).setStatus("1"));
        test2Service.updateT3AndT4();
    }

    @Override
    @Transactional(rollbackFor = Throwable.class,propagation = Propagation.REQUIRED)
    public void updateT3AndT4() {
        test3Mapper.updateByPrimaryKeySelective(new Test3().setId(1).setStatus("1"));
        int i=1/0;
        test4Mapper.updateByPrimaryKeySelective(new Test4().setId(1).setStatus("1"));
    }

1

外层方法未回滚,内存方法回滚了。

都为 Propagation.SUPPORTS 级别时👇

	@Override
    @Transactional(rollbackFor = Throwable.class,propagation = Propagation.SUPPORTS)
    public void contain() {
        test1Mapper.updateByPrimaryKeySelective(new Test1().setId(1).setStatus("1"));
        int i=1/0;
        test2Mapper.updateByPrimaryKeySelective(new Test2().setId(1).setStatus("1"));
        test2Service.updateT3AndT4();
    }
	
	@Override
    @Transactional(rollbackFor = Throwable.class,propagation = Propagation.SUPPORTS)
    public void updateT3AndT4() {
        test3Mapper.updateByPrimaryKeySelective(new Test3().setId(1).setStatus("1"));
        int i=1/0;
        test4Mapper.updateByPrimaryKeySelective(new Test4().setId(1).setStatus("1"));
    }

2
内存事务回滚了。

3

实际使用上,一般都为 默认传播级别就可以了,因为需要开启事务时,会把关联表的操作放在同一个事务方法里。

  • 可能在使用上,有时会选择更细粒度的,模板事务 TransactionTemplate ,因为方法中如果包含一些业务数据计算,是可以不包含在事务里面的,因为我们的目的基本是为了保持数据的一致性!
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值