事务@Transactional
第一个问题:
@Transactional是遇到RuntimeException时回滚事务
@Transactional(rollbackFor = Exception.class)是遇到Exception时回滚事务
能不能这样理解,被事务标记的方法,只要方法名后面没有跟抛出异常语句,@Transactional和@Transactional(rollbackFor = Exception.class)效果是一样的?
比方说
@Transactional public String orderCreate() { }
和
@Transactional(rollbackFor = Exception.class) public String orderCreate() { }
上面两个效果一样?
public String orderCreate() throws IOException { }
只有像这样,方法抛出非RuntimeException的情况下,效果才会不一样?
第二个问题:
这里购买商品,扣库存操作,是先读取数据库中的数据,然后在java里,给product的属性重新赋值,再用
productMapper.updateByPrimaryKeySelective(product);
方法把商品写入数据库,但是这个方法sql语句只是 “set 库存=某个值”。
考虑到抢购这样的高并发场景(不使用Redis,单纯用MySql),应该设置事务隔离级别,但是应该使用哪种隔离级别?
自己模拟高并发场景测试过,如果用READ_UNCOMMITTED,READ_COMMITTED,REPEATABLE_READ都会导致数据错乱,1份库存,可以生成多张订单。
如果用SERIALIZABLE,虽然数据不会有问题,但是体验很差,高并发时,一个人在操作,同一时间的其他所有人都报错(不是等待后按顺序执行扣库存,而是等待后报错),即使在库存充足的情况下,也需要等这个人操作全部结束后,才允许新发来请求执行。
感觉这四种隔离级别都不能满足需求。
归根到底,问题还是出在sql语句上。
productMapper.updateByPrimaryKeySelective(product);
这个方法的sql语句只是简单的 “set 库存=某个值”。
我觉得这里扣库存操作,应该自己写个独立的sql语句 “set 库存=(库存 - 本次购买数据量)”,然后再查询一次该商品库存,如果库存小于0,则回滚。这样搭配READ_COMMITTED或者REPEATABLE_READ,即保证高并发,又保证数据安全。
但是我一直没有试验出来READ_COMMITTED和REPEATABLE_READ的区别,针对这个问题,好像两者效果一样。
正在回答 回答被采纳积分+1
同学你好,关于同学的问题:
1、当方法抛出RuntimeException异常时,@Transactional和@Transactional(rollbackFor = Exception.class)是一样的。方法抛出非RuntimeException的情况下,效果不同。具体抛出什么异常,是方法中的代码造成的。
2、多数应用程序,可以优先考虑把数据库系统的隔离级别设为Read Committed。
读已提交解决了脏读现象,但是可能会出现不可以重复读和幻读现象。
可重复读解决了脏读和不可以重复读的问题,但是可能出现幻读现象。
事务的执行具有随机性,可能多次执行的结果相同。
祝:学习愉快~
- 参与学习 人
- 提交作业 9393 份
- 解答问题 16556 个
综合就业常年第一,编程排行常年霸榜,无需脱产即可学习,北上广深月薪过万 无论你是未就业的学生还是想转行的在职人员,不需要基础,只要你有梦想,想高薪
了解课程
恭喜解决一个难题,获得1积分~
来为老师/同学的回答评分吧
0 星