属于事务四大特性之一的隔离性(isolation),解决两个并发事务同时访问数据库表相同的行时,可能存在的问题

目录

基础

四大隔离级别

隔离级别与一致性关系

如何设置

作用范围

补充:

额外:

第一类丢失更新

第二类丢失更新


基础

四大隔离级别

1、 read uncommitted(读未提交)

- 事务A和事务B,事务A未提交的数据,事务B可以读取到
- 这里读取到的数据叫做“脏数据”
- 这种隔离级别最低,这种级别一般是在理论上存在,数据库隔离级别一般都高于该级别

问题:引发脏读;
原因:读取了未提交的数据

1  脏读
  脏读是指在一个事务处理过程里读取了另一个未提交的事务中的数据。
  当一个事务正在多次修改某个数据,而在这个事务中这多次的修改都还未提交,这时一个并发的事务来访问该数据,就会造成两个事务得到的数据不一致。例如:用户A向用户B转账100元,对应SQL命令如下
    update account set money=money+100 where name=’B’;  (此时A通知B)
    update account set money=money - 100 where name=’A’;
  当只执行第一条SQL时,A通知B查看账户,B发现确实钱已到账(此时即发生了脏读),而之后无论第二条SQL是否执行,只要该事务不提交,则所有操作都将回滚,那么当B以后再次查看账户时就会发现钱其实并没有转。

2、read committed(读已提交)

- 事务A和事务B,事务A已提交的数据,事务B才能读取到
- 这种隔离级别高于读未提交
- 换句话说,对方事务提交之后的数据,我当前事务才能读取到
- 这种级别可以避免“脏数据”
- Oracle默认隔离级别
- 是大多数数据库系统默认的隔离级别,但不是MySQL默认的

问题:引发不可重复读,不可重读读意味着我们同一事务执行完全相同的select语句时可能看到不一样的结果。
原因可能有:
    (1)有一个交叉的事务有新的commit,导致了数据的改变;
    (2)一个数据库被多个实例操作时,同一事务的其他实例在该实例处理其间可能会有新的commit,多个commit提交时,只读一次出现结果不一致


2  不可重复读
  不可重复读是指在对于数据库中的某个数据,一个事务范围内多次查询却返回了不同的数据值,这是由于在查询间隔,被另一个事务修改并提交了。
  例如事务T1读取一行记录,紧接着事务T2修改了T1刚刚读取的记录,然后T1再次查询,发现与第一次读取的记录不同。
  不可重复读和脏读的区别是,脏读是某一事务读取了另一个事务未提交的脏数据,而不可重复读则是读取了前一事务提交的数据。

3、repeatable read(可重复读)

- 事务A和事务B,事务A提交之后的数据,事务B读取不到
- 事务B是可重复读取数据
- 这种隔离级别高于读已提交
- 换句话说,对方提交之后的数据,我还是读取不到
- 这种隔离级别可以避免“不可重复读取”,达到可重复读取
- 它确保同一事务的多个实例在并发读取数据时,看到同样的数据行
- MySQL默认事务隔离级别

问题:幻读(Phantom Read)
原因:当用户读取某一范围的数据行时,另一个事务又在该范围内插入了新行,当用户再读取该范围的数据行时,会发现有新的“幻影” 行
解决:InnoDB和Falcon存储引擎通过多版本并发控制(MVCC,Multiversion Concurrency Control)机制解决了该问题


3  幻读
  幻读是事务非独立执行时发生的一种现象。
例如事务T1读取一条指定where条件的语句,返回结果集。此时事务T2插入一行新记录,恰好满足T1的where条件。然后T1使用相同的条件再次查询,结果集中可以看到T2插入的记录,这条新纪录就是幻像。
幻读和不可重复读都是读取了另一条已经提交的事务(这点就脏读不同),所不同的是不可重复读查询的都是同一个数据项,而幻读针对的是一批数据整体(比如数据的个数)。

4、serializable(串行化)

- 事务A和事务B,事务A在操作数据库时,事务B只能排队等待
- 这种隔离级别很少使用,吞吐量太低,用户体验差
- 这种级别可以避免“幻像读”,每一次读取的都是数据库中真实存在数据,事务A与事务B串行,而不并发

这是最高的隔离级别
它通过强制事务排序,使之不可能相互冲突,从而解决幻读问题。简言之,它在每个读的数据行上加上共享锁。

问题:可能导致大量的超时现象和锁竞争

隔离级别与一致性关系

mysql查看数据库事务隔离级别 mysql数据库的事务隔离级别_数据


如何设置

方式一:可以在my.ini文件中使用transaction-isolation选项来设置服务器的缺省事务隔离级别。

该选项值可以是:

  • – read-uncommitted
  • – read-committed
  • – repeatable-read
  • – serializable

•   例如:

transaction-isolation = READ-COMMITTED

方式二:通过命令动态设置隔离级别
• 隔离级别也可以在运行的服务器中动态设置,应使用SET TRANSACTION ISOLATION LEVEL语句。
• 其语法模式为:

SET [GLOBAL | SESSION] TRANSACTION ISOLATION LEVEL <isolation-level>

其中的<isolation-level>可以是:

  •     –   READ UNCOMMITTED
  •     –   READ COMMITTED
  •     –   REPEATABLE READ
  •     –   SERIALIZABLE
例如: SET TRANSACTION ISOLATION LEVEL REPEATABLE READ;

作用范围

事务隔离级别的作用范围分为两种: 

  1. –   全局级:对所有的会话有效 
  2. –   会话级:只对当前的会话有效 

如:

设置会话级隔离级别为READ COMMITTED :

mysql> SET TRANSACTION ISOLATION LEVEL READ COMMITTED;
或:
mysql> SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;

设置全局级隔离级别为READ COMMITTED : 

mysql> SET GLOBAL TRANSACTION ISOLATION LEVEL READ COMMITTED;

注意:隔离级别的设置只对当前链接有效。对于使用MySQL命令窗口而言,一个窗口就相当于一个链接,当前窗口设置的隔离级别只对当前窗口中的事务有效;对于JDBC操作数据库来说,一个Connection对象相当于一个链接,而对于Connection对象设置的隔离级别只对该Connection对象有效,与其他链接Connection对象无关。


补充:

        1、事务隔离级别为读提交时,写数据只会锁住相应的行

        2、事务隔离级别为可重复读时,如果检索条件有索引(包括主键索引)的时候,默认加锁方式是next-key 锁;如果检索条件没有索引,更新数据时会锁住整张表。一个间隙被事务加了锁,其他事务是不能在这个间隙插入记录的,这样可以防止幻读。

        3、事务隔离级别为串行化时,读写数据都会锁住整张表

   4、隔离级别越高,越能保证数据的完整性和一致性,但是对并发性能的影响也越大。

一个数据库可能拥有多个访问客户端,这些客户端并发访问数据库时,若没有采取必要的隔离措施,存在以下问题,这些问题分为5类,包括3类数据读问题:脏读、不可重复读和幻读。两类数据更新问题:第一类丢失更新、第二类丢失更新。

第一类丢失更新

A事务撤销时,把已经提交的B事务的更新数据覆盖了。例如:

mysql查看数据库事务隔离级别 mysql数据库的事务隔离级别_mysql_02

这时候取款事务A撤销事务,余额恢复为1000,这就丢失了更新。

第二类丢失更新

A事务覆盖B事务已经提交的数据,造成B事务所做的操作丢失

mysql查看数据库事务隔离级别 mysql数据库的事务隔离级别_mysql_03

为了解决上述问题,数据库通过锁机制解决并发访问的问题。根据锁定对象不同:分为行级锁和表级锁;根据并发事务锁定的关系上看:分为共享锁定和独占锁定,共享锁定会防止独占锁定但允许其他的共享锁定。而独占锁定既防止共享锁定也防止其他独占锁定。为了更改数据,数据库必须在进行更改的行上施加行独占锁定,insert、update、delete和selsct for update语句都会隐式采用必要的行锁定。

但是直接使用锁机制管理是很复杂的,基于锁机制,数据库给用户提供了不同的事务隔离级别,只要设置了事务隔离级别,数据库就会分析事务中的sql语句然后自动选择合适的锁。
不同的隔离级别对并发问题的解决情况如图:

mysql查看数据库事务隔离级别 mysql数据库的事务隔离级别_数据_04

注意:事务的隔离级别和数据库并发性是成反比的,隔离级别越高,并发性越低。