参考帖子:http://blog.csdn.net/winy_lm/article/details/50403264
?
举个例子: 假设商品表单products 内有一个存放商品数量的quantity ,在订单成立之前必须先确定quantity 商品数量是否足够(quantity>0) ,
然后才把数量更新为1。
不安全的做法:
SELECT quantity FROM products WHERE id=3;
UPDATE products SET quantity = 1 WHERE id=3;
为什么不安全呢?
少量的状况下或许不会有问题,但是大量的数据存取「铁定」会出问题。
如果我们需要在quantity>0 的情况下才能扣库存,假设程序在第一行SELECT 读到的quantity 是2 ,看起来数字没有错,但是当MySQL 正准备要UPDATE 的时候,可能已经有人把库存扣成0 了,但是程序却浑然不知,将错就错的UPDATE 下去了。
因此必须透过的事务机制来确保读取及提交的数据都是正确的。
实际测试:
loading很久后如下
?
?
?
?
?
项目中测试:
Xml:
?
?
?
?
在项目中无需另外写SET AUTOCOMMIT=0; BEGIN WORK; 只需在查询语句后面加上for update
因为@Transactional已经帮我们完成了这些操作
Controller:
?
测试方法
???????? 同一个项目在两个Tomcat中启动,因为需要在其中一个方法内打断点,所以需要在两个eclipse中操作或者打成war包放入Tomcat/webapps中启动,同时开启两个Tomcat需要更改其中一个的端口号避免端口号占用的问题。
???????? 两个项目都开启好之后,下面正式开启测试。
库存不足时,两个项目的显示:
?
?
?
?
?
库存为1时,其中一个进入方法打断点之后,另一个进行同样的操作:
?
在8081的这个上打上断点,断点打在findById(for update)之后
?
然后进入8080,发现8081断点不放开,这边就一直在加载中。。
?
放开断点之后,8081库存-1?成功,8080也加载完成,显示库存不足,达到我们的要求?
?
?
写在后面:
class="java" name="code">测试去除@Transactional注解之后的效果,在同样的操作下最后都显示“库存 -1 : success”, 这是因为没有Transactional注解下,没有SET AUTOCOMMIT=0; BEGIN WORK;的效果, 导致select..for update没有生效。
?