事务@Transactional

事务@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回答
好帮手慕阿满 2020-09-10 19:44:21

同学你好,关于同学的问题:

1、当方法抛出RuntimeException异常时,@Transactional和@Transactional(rollbackFor = Exception.class)是一样的。方法抛出非RuntimeException的情况下,效果不同。具体抛出什么异常,是方法中的代码造成的。

2、多数应用程序,可以优先考虑把数据库系统的隔离级别设为Read Committed。

读已提交解决了脏读现象,但是可能会出现不可以重复读和幻读现象。

可重复读解决了脏读和不可以重复读的问题,但是可能出现幻读现象。

事务的执行具有随机性,可能多次执行的结果相同。

祝:学习愉快~


  • rock221 #1

    老师,这里直接开启事务也可以了的吧? @Transactional

    2021-06-15 15:51:21
  • 同学的理解是正确的,继续加油。祝学习愉快~

    2021-06-15 17:51:22
问题已解决,确定采纳
还有疑问,暂不采纳

恭喜解决一个难题,获得1积分~

来为老师/同学的回答评分吧

0 星

相似问题

登录后可查看更多问答,登录/注册

请稍等 ...
意见反馈 帮助中心 APP下载
官方微信

在线咨询

领取优惠

免费试听

领取大纲

扫描二维码,添加
你的专属老师