1、首先MYSQL数据库的默认事务隔离级别为:REPEATABLE-READ 可重复读。
2、如果不是上述隔离级别,请先修改隔离级别为可重复读,修改方法如下:
mysql> set session transaction isolation level REPEATABLE READ;
3、开启两个命令行窗口,分别登录mysql,并命名为session1和session2,以模拟两个消费者消费模拟队列的数据(已提前保存好6条队列数据,不再模拟生产者的行为)。注释:id为自增主键、session用来存储sessionId,msg是待消费的数据体,status是消费状态(un_use:未消费,using:消费中,used:已消费)。
4、分别在SESSION1和SESSION2中开启事务,并查询此时队列中的数据状态,可以看到全部为un_use状态。
mysql> start transaction;
5、现在开始消费,session1先消费,假设每次消费2条。
mysql> update user set session=CONNECTION_ID(),status='using' where status='un_use' limit 2;
6、假如此时session2并发消费消息
情况(1)如果session1还没有commit事务,session2需要等待,一直等到session1提交事务(见情况(2)),或者session2超时回滚或重试。
情况(2)如果session1已经commit事务,则神奇的一幕出现了。
可以看到:session2执行update语句更新数据,更新的是id=1008,1009的两条消息!!!(讲道理应该更新1006,1007,为什么会更新1008和1009呢?除非,session2感知到了1006和1007被session1更新过了,但是从select结果上看,session2并没有感知到1006和1007已变化,这是一个神奇的东西,或许和MVCC有关,请懂的大牛们指教!)
7、既然如此,session1和session2都拿到了自己应该处理的消息,那就可以进行消息处理了,处理完消息以后,通过id来更新数据库状态就不存在并发问题了。
8、通过上面两session交替执行更新,可以进行并发更新,周而复始。
9、如果执行过程中session中断,则会造成一部分using状态的数据变成僵尸数据,此时可以结合定时任务,对using数据进行进行扫描。