比如update table1 set filed1 = field1 - 1 where field - 1 >= 0 and id = 1,请问大家这条语句高并发会有风险吗。
例如出现这种情况,filed1 = 1时,两条语句同时判断field1 =1,这时候都会做减法 1-1一次,0-1一次。
我觉得这条语句的成败就在于读的时候是不是排他锁行或者表,但是没有专业的思路
...全文
1226打赏收藏
请教关于动态sql在并发场景下的安全性
比如update table1 set filed1 = field1 - 1 where field - 1 >= 0 and id = 1,请问大家这条语句高并发会有风险吗。 例如出现这种情况,filed1 = 1时,两条语句同时判断field1 =1,这时候都会做减法 1-1一次,0-1一次。 我觉得这条语句的成败就在于读的时候是不是排他锁行或者表,但是没有专业的思路
经过mybatis+spring注解事务写的代码,和用jmeter并发测试(原谅我没有建立专门的表测试,只用了sys_user表的为int类型的user_sex性别字段作为测试字段),结果显示,当user_sex减到0时,对应的insert的条数不多不少等于目标字段的条数,所以现象上说明这条语句是没有并发风险的,原理上请大神们深入的解释下吧。
我之所以提出这个问题,原因是前两天去面试一家知名电商企业,讨论到减库存的问题时,我说我用这种做法,他说这样在超高并发下会出现问题,他建议用乐观锁方式,将时间戳直接拼到where条件中,但是我认为乐观锁在高并发时会造成大量的where条件不成立。
@Transactional
public int updateSexCount(User user) {
//并发减库存
int a = userDao.updateSexCount(user);
if (a >0) {
//如果上条成功,这里就增加一条数据
shopService.insert(new Shop());
}
return a;
}
<update id="updateSexCount" parameterType="xxxx">
update sys_user set user_sex=user_sex - 1 where id = #{id} and user_sex - 1 >=0
</update>
谢谢,虽然update会加锁,但是会不会有可能内部执行的是读值和赋值两个过程呢,就像这样的
START TRANSACTION
1、select myfield from mytable where id = 1 ; 得要myfield的值是比如是1,计算出结果myfiled - 1 = 0
2、update mytable set myfield = 0 where 0>=0 and id = 1;
COMMIT
这时候如果同时并发读,读出来的A执行1,读到值为1,B读到值为1,A加排它锁执行2 update mytable set myfield = 0 where 0>=0 and id = 1 释放排它锁,B加锁执行2 update mytable set myfield = 0 where 0>=0 and id = 1 释放排它锁。
这样无形中对数据库执行了两遍 update mytable set myfield = 0 where 0>=0 and id = 1,虽然结果对于这一行是不影响的。
但是如果事务中还有3、insert into。。。。。。 ,这句根据2返回的成功行数去操作,两个都发生了1行变动,那么就生成两条insert,其实就想要一条的。