一般情况下,mysql Innodb是行级锁,但是在项目中居然出现了死锁,锁表的情况,为什么呢?先看例子:
项目中有个业务逻辑是这样的,添加自选股的时候,查询当前自选股组下面有没有达到最大值,如果未达到最大值,那么此分组下的其他的自选股排序顺序要加1,sql如下:
//根据条件查询当前自选股组下面有多少条自选股
SELECT count(0) FROM t_user_self_stock WHERE user_id = #{userId} AND block_group_id = #{blockGroupId}
//根据条件查询自选股的条数
UPDATE t_user_self_stock SET stock_sort = stock_sort+1 WHERE user_id = #{useId} AND block_group_id=#{blockGroupId}
如果2个线程同时访问,当第一个线程查询自选股没有达到最大值,更新加1操作,第二个查询的时候也未达到最大值,但第一个更新还没完成,其实第一个线程已经达到了最大值,那第二个查到的数据,就是脏数据。mysql使用innodb引擎可以通过索引数据行加锁。sql修改如下:
SELECT count(0) FROM t_user_self_stock WHERE user_id = #{userId} AND block_group_id = #{blockGroupId} for update
UPDATE t_user_self_stock SET stock_sort = stock_sort+1 WHERE user_id = #{useId} AND block_group_id=#{blockGroupId}
commit;
第二个线程执行到select 语句的时候就会处于等待状态知道第一个执行commit;从而保证了第二个线程不会读到第一个线程修改前的数据。这样是不是就可以了,继续往下看: