springboot 事务与并发及回滚

一、事务四大特性

1、原子性 atomicity:事务不可分,提交便一次性提交

2、一致性 consistency:事务执行前后数据保持完整性,经典例子是银行转账前后双方的总额需保持不变,类似能量守恒

3、隔离性 isolation:不同事务执行之间需保持隔离,不相互影响

4、持久性 durability:事务结束造成的改变便持久到数据库

二、并发问题

1、脏读①:A读到B还未提交的事务,如果B回滚操作,此时A读到的便是无效的数据

2、丢失更新②:A和B同时修改同一条数据,A先修改,B后修改,最后B要回滚结果把A更新的给丢了(一类丢失);A和B同时修改同一条数据,A先修改,B后修改,最后B把A的修改给覆盖了(二类丢失

3、不可重复读③:A事务的内读取数据,然后B事务此时修改了某一数据,A的同个事务再读一次发现数据已经变化(和“幻读”的差别,这个强调更新)

4、幻读④:A事务的内读取数据,此时B插入了一条新数据,A的同个事务再读一次数据就多了一条(和“不可重复”差别,这个强调插入、删除)

三、事务隔离级别 Isolation,指并发事务之间的隔离程度(后面的编号指在该级别下会出现的问题,对应上方并发问题的编号)

1、read_umcommited:①②③④

2、read_commited:②③④

3、repeatbale read:④(这种是对于普遍的数据库而言,mysql的 Innodb有特殊在 此级别下能用 mvcc解决快照读的幻读情景,用间隙锁解决当前读的情景

4、serializble:

https://github.com/Yhzhtk/note/issues/42

https://tech.meituan.com/2014/08/20/innodb-lock.html

四、事务传播行为 Propagation,指开始当前事务之前,一个事务上下文已经存在,此时选择的事务执行方式

1、REQUIRED(required):先选当前事务,如果没有就新建事务

2、SUPPORTS(supports):选当前事务,如果没有就不用事务

3、MANDATORY(mandatory):选当前事务,如果没有就抛异常

4、REQUIRED_NEW(required_new):直接新建事务,当前的事务挂起

5、NOT_SUPPORTED(not_supported):非事务执行,当前事务挂起

6、NEVER(never):非事务执行,如果当前有就抛异常

7、NESTED(nested):当前事务嵌套一个事务,如果没有就新建事务

五、Springboot增加事务处理

1、在项目启动类增加注解 @EnableTransactionManagement ,打开事务管理

  

2、指定事务管理器,springboot的事务管理器都继承于 PlatformTransactionManager,而且会自动注入,如果是引入了 spring-boot-starter-jdbc,则使用的是 DataSourceTransactionManager,如果是引入了 spring-boot-starter-data-jpa,则使用的是 JpaTransactionManager。当然我们也可以自己定义Bean,自己决定注入哪个,比如在启动类定义事务管理器的Bean,如下:

@Bean
public PlatformTransactionManager txManager(DataSource ds){
	return new DataSourceTransactionManager(ds);
}

3、在需要增加事务处理的地方增加 @Transactional ,默认处理级别是 RuntimeException

@Transactional
public void insertData(){
	String sql = "insert into product values ('128','sadd','saf')";
	Integer result = jdbcTemplate.update(sql);
	throw new RuntimeException("异常");
}
  • 如果需要回滚Exception的级别,修改以下注解
@Transactional(rollbackFor = Exception.class)
  • 其他的事务传播行为及隔离级别配置参考上方第三第四点

4、事务回滚失败的几种情况

  • 在方法内把异常catch掉了,这样是不会回滚的,一般做法是把 try{}catch 放到controller层,service层用@Transactional
@Transactional
public void insertData(){
//这样会回滚失效
	try {
		String sql = "insert into product values ('129','sadd','saf')";
		Integer result = jdbcTemplate.update(sql);
		throw new RuntimeException("异常");
	} catch (Exception e) {
		e.printStackTrace();
	}
}
  • 假如在同个类内部有函数的调用,@Transactional注解需要注解在第一个进入该类的函数,否则会回滚失效,如下这样才可以
@Autowired
JdbcTemplate jdbcTemplate;
@Transactional(rollbackFor = Exception.class)
public void testInsert() throws Exception{
	insert();
}

public void insert() throws Exception{
	insertData();
}

public void insertData() throws Exception{
	String sql = "insert into product values ('133','sadd','saf')";
	Integer result = jdbcTemplate.update(sql);
	throw new Exception("异常");
}
  • @Transactional注解的方法所属类需要注解了@Service或@Component等交给spring容器管理的注解
  • @Transactional所注解的方法需要是public的,否则也回滚不了
  • 数据库表引擎如果是 MyIsam 是不支持事务的,改为 InnnoDB(千万注意除了查数据库,还有可能表单独的引擎不一样

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值