本实验原创,MYSQL用的引擎是InnoDB引擎。执行SQL语句用的是Navicat(这个不会影响实验结果,但是引擎可能会影响)。


       刚刚看了《

MySQL数据库事务隔离级别

》一文,吓出了一身冷汗,里面MYSQL对于REPEATABLE-READ的处理,在一个事务读取某行时另一个事务要对该行进行写操作竟然不会被挂起,而是可以成功执行,只是即使写操作的事务即使提交了也不影响读操作事务的读取。但是,这就留下了一个隐患,如下:

       先建立一张名为test的表,该表有两个字段aaa和bbb,都是整形。该表只有一条记录,如下:

 

mysql可重复读会加行读锁吗 mysql可重复读解决写问题_MySQL


      然后分别开始两个事务:


事务A:

mysql可重复读会加行读锁吗 mysql可重复读解决写问题_字段_02




事务B:

mysql可重复读会加行读锁吗 mysql可重复读解决写问题_字段_03



然后事务A和B分别执行以下查询语句:

事务A:

mysql可重复读会加行读锁吗 mysql可重复读解决写问题_隔离级别_04



事务B:

mysql可重复读会加行读锁吗 mysql可重复读解决写问题_字段_05


到这一步还没问题,好了,重头戏开始:


事务A执行更新操作,顺便检查以下结果,然后提交:

mysql可重复读会加行读锁吗 mysql可重复读解决写问题_字段_06



然后事务B执行查询操作,然后让bbb=bbb-1,然后再执行查询操作,最后提交(注意。两张图片一张是结果1,一张是结果2,分别代表两个select语句):



mysql可重复读会加行读锁吗 mysql可重复读解决写问题_MySQL_07

    

mysql可重复读会加行读锁吗 mysql可重复读解决写问题_隔离级别_08


换句话说,111-1=0,这种小学生都不会犯的错……


       可重复读,要求两次读取的结果一样。理所应当,出现计算时,两次读取的结果也应当符合,这点MSSQL就做得很好,他会判断出有死锁,然后选择一个进程作为牺牲进程,而不是像MYSQL一样在完全不报错的情况下给出错误答案。毕竟在程序中我们经常是取出bbb这个字段进行某种操作(计算)后把结果再次填到bbb的,像MYSQL这样的处理就会导致程序出现错误!同样的,MYSQL中对于READ-COMMIT这个隔离级别的做法也可能会引发问题(但是我想不出会引发什么问题)。当某个事务在对某行进行写操作时,另一个事务对该行进行读操作应该被挂起,而非是读取修改前的数据。


     PS: 刚刚才发现,如果想真正做到可重复读,可在select 语句后手动添加读锁,即select ...... lock in share mode。