spring事务隔离级别是什么,数据库隔离级别是什么,它们有什么关系。我来帮大家理一理。
其实非常简单,spring发送SQL请求和我们用的Navicat 写 set session transaction isolation level 具体级别
start transaction
是一样的,实际上就是spring 使用了 MySQL提供的标准接口,说白了就是告诉MySQL 使用什么事务隔离级别而已。
脏读:一事务对数据进行了改更改,但未提交,另一事务可以读取到未提交的数据。如果第一个事务这时候回滚了,那么第二个事务就读到了脏数据。这种级别下读的是内存。
疑问1:脏读,为啥别人能看到我未提交的数据?
答: 因为修改是在内存中修改的,没有提交到文件系统上,也就是没有写到日志里。说白就是读取到了临时数据。
提交读:一个事务中发生了两次读操作,第一次读操作和第二次操作之间,另外一个事务对数据进行了修改并且提交,这时候两次读取的数据是不一致的。这种级别下能读取到其他事物提交的结果。 这种级别下修改操作读的是数据库的文件内容
可重复读:一个事物内,不管读多少次,读到的结果都是一样的。MySQL通过多板块控制机制解决了这个问题,一致性读快照。当事务A做了更新操作的时候事务B也试图去对这条数据做更新是无法执行的,它会等待事务A提交后它才能提交.但是后面提交的会覆盖前面提交的。为了解决这个问题,mybatis 可以设置一个version来做乐观锁比较。
我们来试着做下试验,没有引来乐观锁机制之前:
我们开启一个事务A,并修改数据,
SET session Transaction Isolation Level REPEATABLE READ;
start transaction;
select * from man_1 where id =1;
update man_1 set name = '陈秋妹35' where id =1 ;
到此我们并没有提交事务B,接下来我们用另外一个窗口打开,
SET session Transaction Isolation Level REPEATABLE READ;
start transaction;
update man_1 set name = '陈秋妹36' where id =1;
select *from man_1;
也没有提交,这时候,B窗口的更新语句是没办法执行的,堵塞了,因为更改同一行数据。
然后我们提交A commit;
提交A后B中的更新语句得以执行,不再堵塞,这个时候B的事务还没有提交,提交B,commit,我们发现数据库的内容是B提交的内容,说明 A开始,B开始,A提交,B提交模式,B会覆盖A,在默认隔离级别下,他们读到的数据是隔离的,mvcc机制,读的时候是不知道对方改了啥数据,就算A事务提交了,B也是读不到的,同一个事务内读取的内容一样,那怎么防止这种情况发生呢,就要用mybaits乐观锁机制,加个版本来判断,
A开始,只做更新
SET session Transaction Isolation Level REPEATABLE READ;
start transaction;
select * from man_1 where id =1;
update man_1 set name = '陈秋妹35',version = version+1 where id =1 ;
select *from man_1;
开始B 事务,阻塞了
提交A事务,观察B
没有版本号控制,更新可以执行,我们加上版本号控制,
加上了版本号控制后,没有执行成功了,影响行号为0,
很明显version 这个时候数据库中的是2,二比二小,如果没有A事务的存在的话,那么数据库中的version是1,会比二小。
很明显,在这种mvcc机制下,同一个事务下每次读都是一样的,也就只限于读的时候。
结论:mvcc机制可以保证事务内读多少次都是读到一样的值,但是别的事务并发更新并提交的值它看不见,这个时候如果继续使用mybatis 原来的更新法去更新数据库,很明显,要覆盖前面事务的提交结果,
因为mybatis 查询出一个结果后喜欢用,updatebyprimarykeyselective()去更新,这个方法就是用加载出来,修改,后更新回数据库,这里如果不加version控制,将会覆盖其同一时间段内他事务的提交结果。
这里还会容易造成死锁问题,比如A开始,B开始, A改了ID等于1的数据,B改了ID等于2的数据,A又去改了ID等于2的数据,这个时候A会堵塞,B又去改ID等于1的数据,B也进入了堵塞,这个时候就会陷入A等B事务提交释放ID等于2的行锁,B同时也等待A释放数据ID等于1的行锁,进入了死循环中,哈哈哈。mvcc不是万能的,希望各位深刻理解数据库事务本质。
幻读和可重复读是一个级别:第一个事务对一定范围的数据进行批量修改,第二个事务在这个范围增加一条数据,别的事务读了两次,发现多了一条数据,感觉出现了幻觉一样。网上说MySQL使用间隙锁锁定附近的行,防止事务在锁定范围内插入数据。解决了幻读问题。不过本人亲测,发现这条数据的确是插入了数据库,因为事务提交后再次查询就能查出这条数据,所以上面加锁防止插入并不对,而是版本号条件过滤掉了,应该是MySQL的多版本控制机制在查询的时候带了版本号查询,所以没有查出最后插入的数据,从而搞定了幻读。希望能帮到大家,以上言论均经过亲自测试过的。不是胡说八道。
总结:MySQL 通过多板块控制机制搞定了 重复读和幻读问题。减少了锁的使用,提高了系统性能。
普通的select查询是不加锁的,读的都是快照,所以读几次都是一样的。当事务中包含更新 ,删除的时候是一致性读文件,mysql通过mvcc实现一致性非锁定读,就是在不修改的情况是是不加锁的,读的是快照,所以读几次都一样,实现了可重复读和幻读。