innodb 事务有四个隔离级别,分别为:未提交读、提交读、重复读与序列化
由于隔离级别的不同,会导致如下问题:脏读、不可重复读、幻读。
脏读 :指当前事务能看到其他事务还没Commit的内容。
不可重复读 :同一个事务中,分别两次查询相同的一行数据,看到的结果不一致。
幻读 :幻读指的是一个事务在前后两次查询同一个范围的时候,后一次查询看到了前一次查询没有看到的行。
不可重复读和幻读最大区别 :不可重复读重点在于update和delete,而幻读的重点在于insert,也有说法是幻读 侧重行发生了变化;不可重复读侧重某行数据的修改。不可重复读是修改了存在的数据,导致两次查看不一致,幻读是新增了之前不存在的数据。
下面一一解释各个隔离级别会产生的问题与如何解决脏读、不可重复读、幻读
事务中的修改,即使没有提交,其他事务也可以看得到,会 导致“脏读”、“幻读”和“不可重复读取” 。
一个事务不会读到另一个并行事务已修改但未提交的数据,避免了“脏读取”,但不能避免“幻读”和“不可重复读取”。
为什么无不能避免幻读和不可重复读?
因为每次读取都会重新生成一个快照,所以每次快照都是最新的,也因此事务中每次SELECT也可以看到其它已commit事务所作的更改;
这是MySQL中InnoDB默认的隔离级别。从读的角度看, 快照会在事务中第一次SELECT语句执行时生成,只有在本事务中对数据进行更改才会更新快照 ;
RR级别的事务隔离可以解决脏读和不可重复读,他通过MVVC解决了 快照读情况下的幻读问题 ,当前读下的幻读是以来Innodb的锁机制实现的。所以总结起来就是:
1在快照读情况下,Mysql通过MVVC来避免幻读。
2在当前读的情况下,Mysql通过锁机制来避免幻读。
可以通过下面SQL进行测试
上述例子,事务2插入语句并且提交了,事务1通过update语句能更新到,那是因为update语句是当前都,他能读到现在最新的数据并加锁。下面语句要达到可重复度的级别,需要这样修改:
所以,网上很多说可重复读通过MVVC机制解决了幻读问题,其实是不正确的,锁机制才是解决可重复读下幻读问题的重大功臣
这里补充说明下当前读与快照读是什么!
快照读 :读取专门的快照 (对于RC,快照(ReadView)会在每个语句中创建。对于RR,快照是在事务启动时创建的)。简单的select *** 作即可。
当前读 :读取最新版本的记录, 没有快照。 在InnoDB中,当前读取根本不会创建任何快照。语句包括:select lock in share mode、select for update、inset、update、delete。当前读是通过手动加record lock(记录锁)和gap lock(间隙锁)来实现的。
待续-后续讲下事务的原理
这个过程实际上会涉及到 脏写、脏读、不可重复读、幻读 ,四种问题。
MySQL默认的事务隔离级别是RR(可重复读),而且 MySQL的RR级别是可以避免幻读发生 。也就是说,MySQL里执行的事务,默认情况下不会发生脏写、脏读、不可重复读和幻读的问题。
如何修改MySQL隔离级别?
Spring中默认隔离级别与MySQL一致,Spring中如何修改?
简单来说,就是执行一个事务的时候,就生成一个ReadView,里面比较关键的东西有4个:
示例:
通过undo log多版本链条,加上你开启事务时候生产的一个ReadView,然后再有一个查询的时候,根据ReadView进行判断的机制,你就知道你应该读取哪个版本的数据。
首先我们先要明白,多个事务并发运行的时候,同时读写一个数据,可能会出现脏写、脏读、不可重复读、幻读几个问题。
针对这些问题,所以才有RU、RC、RR和串行四个隔离级别。
然后MySQL实现MVCC机制的时候,是 基于undo log多版本链条+ReadView机制 来做的,默认的RR隔离级别,就是基于这套机制来实现的,依托这套机制实现了RR级别,除了避免脏写、脏读、不可重复读,还能避免幻读问题。因此一般来说我们都用默认的RR隔离级别就好了。
这个很简单啊,你在添加记录前,先搜索一下数据库中是否已经存在这个记录,有就提示,没有就保存新纪录。例子:(由于数据库 *** 作引擎不同,可能不适合你,仅仅是个例子)
rsopen "select from 用户表 where 用户名='" & username & "' and 密码='" & password & "'",conn,1,1
if rseof then
connexecute "insert into 用户表 (用户名,密码) values ('" & username & "','" & password & "')"
else
msgbox "用户已存在!"
end if
rsclose1脏读:脏读就是指当一个事务正在访问数据,并且对数据进行了修改,而这种修改还没有提交到数据库中,这时,另外一个事务也访问这个数据,然后使用了这个数据。2不可重复读:是指在一个事务内,多次读同一数据。在这个事务还没有结束时,另外一个事务也访问该同一数据。那么,在第一个事务中的两次读数据之间,由于第二个事务的修改,那么第一个事务两次读到的的数据可能是不一样的。这样就发生了在一个事务内两次读到的数据是不一样的,因此称为是不可重复读。例如,一个编辑人员两次读取同一文档,但在两次读取之间,作者重写了该文档。当编辑人员第二次读取文档时,文档已更改。原始读取不可重复。如果只有在作者全部完成编写后编辑人员才可以读取文档,则可以避免该问题。3幻读:是指当事务不是独立执行时发生的一种现象,例如第一个事务对一个表中的数据进行了修改,这种修改涉及到表中的全部数据行。同时,第二个事务也修改这个表中的数据,这种修改是向表中插入一行新数据。那么,以后就会发生 *** 作第一个事务的用户发现表中还有没有修改的数据行,就好象发生了幻觉一样。例如,一个编辑人员更改作者提交的文档,但当生产部门将其更改内容合并到该文档的主复本时,发现作者已将未编辑的新材料添加到该文档中。如果在编辑人员和生产部门完成对原始文档的处理之前,任何人都不能将新材料添加到文档中,则可以避免该问题。补充:基于元数据的Spring声明性事务:Isolation属性一共支持五种事务设置,具体介绍如下:lDEFAULT使用数据库设置的隔离级别(默认),由DBA默认的设置来决定隔离级别lREAD_UNCOMMITTED会出现脏读、不可重复读、幻读(隔离级别最低,并发性能高)lREAD_COMMITTED会出现不可重复读、幻读问题(锁定正在读取的行)lREPEATABLE_READ会出幻读(锁定所读取的所有行)lSERIALIZABLE保证所有的情况不会发生(锁表)不可重复读的重点是修改:同样的条件,你读取过的数据,再次读取出来发现值不一样了幻读的重点在于新增或者删除同样的条件,第1次和第2次读出来的记录数不一样
错误的是C。
Read uncommitted (读未提交):最低级别。
Read committed (读已提交):读已提交,可避免脏读情况发生。
Repeatable Read(可重复读):确保事务可以多次从一个字段中读取相同的值,在此事务持续期间,禁止其他事务对此字段的更新,可以避免脏读和不可重复读,仍会出现幻读问题。
Serializable (串行化):最严格的事务隔离级别,要求所有事务被串行执行,不能并发执行,可避免脏读、不可重复读、幻读情况的发生。
扩展资料:
数据库的事务隔离越严格,并发副作用越小,但付出的代价也就越大,因为事务隔离实质上就是使事务在一定程度上 “串行化”进行,这显然与“并发”是矛盾的。同时,不同的应用对读一致性和事务隔离程度的要求也是不同的,比如许多应用对“不可重复读”和“幻读”并不敏感,可能更关心数据并发访问的能力。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)