欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

事务可重复读采坑

程序员文章站 2022-05-29 09:54:32
1. 事务可重复读采坑 1.1. 问题 1. 今天碰到个事务幻读的情况,不容易啊,这不是事务间造成的问题,而是rpc调用产生的问题,实际上业务比较规范也不会出现这样的问题。 2. 具体情况是系统A方法a开启 事务,在事务方法中rpc调用了系统B,生成了一条订单,而之后系统A又用sql查询了这条订单, ......

1. 事务可重复读采坑

1.1. 问题

  1. 今天碰到个事务幻读的情况,不容易啊,这不是事务间造成的问题,而是rpc调用产生的问题,实际上业务比较规范也不会出现这样的问题。
  2. 具体情况是系统a方法a开启required事务,在事务方法中rpc调用了系统b,生成了一条订单,而之后系统a又用sql查询了这条订单,会发现根本查不到

1.2. 原因

  • 通过select @@tx_isolation;查询mysql的事务隔离情况会发现,mysql默认是repeatable-read可重复读,映射到代码就是在一个事务内,用同样的条件查询数据库查询到的数据是相同的,哪怕别的系统在事务期间插入了数据,你也读不到

1.3. 解决办法

  • mysql使用这样的隔离级别是有道理的,避免重复读取的不准确,只要这个库都归一个系统管理,我们就可以避免我上述的问题
  • 但既然我现在的遗留业务已经成为了这样的逻辑,在不能修改其它系统的前提下,我只能在代码上下功夫,我对读取订单数据的方法c设置了传播级别为requires_new,也就是新起一个事务,那它就不会受到父事务的影响,还要确保进入该方法前插入订单已提交就行
  • 但这样带来的问题是,方法c若执行正确,但包裹了方法c的方法a中其它行报错,则不能回滚方法方法a的执行内容
  • 这样我又需要写额外的补偿代码,当方法a执行错误,且问题不是在方法c时,我要跳过方法c进行方法调用补偿

1.4. 总结

  • 搞的这么复杂,实际上上面的改造在可以动其他系统的情况下,最简单就是获取订单信息不应该系统a来写sql读,既然系统b管理了订单表那么关于它的增删改查都由它提供就不会产生上述问题了