您的位置:首页 > 数据库 > MySQL

mysql事务隔离性(mysql transaction isolation level)

2016-05-12 19:13 441 查看
参考资料
主要参考
1.shared locks and exclusive locks http://stackoverflow.com/questions/11837428/whats-the-difference-between-an-exclusive-lock-and-a-shared-lock 2.SET TRANSACTION ISOLATION LEVEL (Transact-SQL) https://msdn.microsoft.com/en-us/library/ms173763.aspx 3.mysql高性能开发第一章节
4.non-repeatable read 定义参考wiki https://en.wikipedia.org/wiki/Isolation_(database_systems) 
次要参考
1.Details and Usage of Isolation Levels https://dev.mysql.com/doc/refman/5.6/en/set-transaction.html 
一.关于shared locks and exclusive locks
Think of a lockable object as a blackboard (lockable) in a class room
containing a teacher (writer) and many students (readers).

While a teacher is writing something (exclusive lock) on the board:
Nobody can read it, because it's still being written,
and she's blocking your view
=> If an object is exclusively locked,
shared locks cannot be obtained.
Other teachers won't come up and start writing either, or the board becomes unreadable,and confuses students
=> If an object is exclusively locked, other exclusive locks cannot be obtained.

When the students are reading (shared locks) what is on the board:
They all can read what is on it, together => Multiple shared locks can co-exist.
The teacher waits for them to finish reading before she clears the board to write more
=> If one or more shared locks already exist, exclusive locks cannot be obtained.

即:
写锁(排它锁exclusive locks)
读锁(共享锁shared locks)

在写时候
add exclusive locks
shared locks cannot be obtained
exclusive locks cannot be obtained

在读的时候
add shared locks
shared locks can be obtain
exclusive locks cannot be obtained
这里也更明白exclusive(排斥的,就想这门上加了) shared(在一个事务上,大家可以共享多把锁)

二. 事务
事务是为了保证原子操作,但本身有1...N statement.所以肯定是有N个操作的。
事务1,事务2时并行的,不是串行的接口
事务1:                                              |事务2
start                                          |start
select * from student where name='zhang%'      |update student set name='abc' where name ='zhang%'
other statements.                              |other statements.
commit                                         |commit

二.事务与锁
1. 锁与事务
1) 事务中未必对每个statement(单步代码涉及的表中的数据)加锁,后面我们简称单步锁,可能加也可能不加,这句isolation level有关
2) 即使事务中对每个statement(单步代码涉及的表中的数据)加锁,锁的生存时间也未必规定一定是整个事务中。
即有些锁会在事务中增加,在该事务未结束之前,会被释放
示例:
假设表中有zhang1,zhang2.
事务1:
start
select * from student where name='zhang%'表中的zhang1,zhang2数据加shared lock 行锁。
释放表中的zhang1,zhang2数据加shared lock 行锁
other statements.
commit

假设表中有zhang1,zhang2.

2. 锁在事务中一直存在的作用:
2.1 事务中exlusive locks产生到结束期间,exlusive locks 一直存在
(即 exlusive locks are held until the transaction completes.)
即对事务中已modify的数据,在该事务结束之前,在不允许其他事务去读。

示例1:exclusive locks 是如何解决事务中已 modify 的数据的可读性的。
我们给事务加了 exlusive locks.
假设表中有zhang1,zhang2
事务1:                                               |事务2
|start
start                                            |update student set name='abc' where id=9
select * from student where id=9(被阻塞)          |

|other statements.
|commit
select * from student where id=9(重启)           |
//we get:{9}                                     |
other statements.                                |
commit                                           |

示例2:exclusive locks 是挡不住已读数据被更改的
------- nonrepeatable read(shared locks or MVCC(后续有详细说明) 才可以解决)
我们给事务加了 exlusive locks.
假设表中有zhang1,zhang2(id=9)
事务1                                                |事务2
start                                            |start
select * from student where id=9//we get{zhang2} |
|update student set name='abc' where id=9
select * from student where id=9(被阻塞)          |
|other statements.
|commit
select * from student where id=9(重启)           |
//we get:{abc}                                   |
other statements.                                |
commit                                           |
说明:
我们两个同样的select结果不一样了。这就是“nonrepeatable read”现象.
nonrepeatable read:
定义:
原文:A non-repeatable read occurs, when during the course of a transaction, a row is
retrieved twice and the values within the row differ between reads.
翻译:non-repeatable read发生在一个事务中,需要检索某一行数据两次。然而两次的结果却不一致的现象
原因:事务1没有获得shared locks .locks被其他事务抢夺(这里是事务2的update)
即[shared locks没有一直存在直到事务结束]。
解决策略:
1).推迟事务2的执行,先执行完事务1.
2).MVCC(后续有详细说明)。 事务2先执行,再执行事务1.如果事务1,事务提交时,会检查他的初始条件是否
都每有变化,如果变化就rallback,否则就执行

示例3:exclusive locks 是挡不住phantom data 的
------ nonrepeatable read 之 phantom 现象
第一种场景[first scenario] 事务内部完成另一个事务的(关于该事务的search query的)modify
我们给事务加了 exlusive locks.
假设表中有zhang1,zhang2
事务1                                                |事务2
start                                            |start
select * from student where name="zhang%"        |
//we get:{zhang1,zhang2}                         |
|update student set name='abc' where id=9
select * from student where name="zhang%"(被阻塞) |other statements.
|commit
select * from student where name="zhang%"(重启)   |
//we get:{zhang1}                                |
other statements.                                |
commit                                           |
分析:
看到了么这里的事务1//we get:{zhang1,zhang2,zhang3},要知道zhang3可是事务2 not commited的数据哦.
这就是 phantom 现象。 phantom 现象说的就是鬼魅一样,事务中有两次search query,两次结果是不一样的。
phantom 现象
定义:
A phantom read occurs when, in the course of a transaction, two identical queries are
executed, and the collection of rows returned by the second query is different from the
first. The phantom reads anomaly is a special case of Non-repeatable reads
”phantom read“发生在一个事务中两个同样的查询,得到的行的集合的结果。两个结果集合不一致的情况。
”phantom read“ 现象也是特殊的nonrepeatable现象
原因:当前事务内部完成另一个事务的(关于该事务的search query的条件内的)modify并在当前事务完成之前完成。
即没有“事务开始 shared locks 产生到结束期间,shared locks 一直存在”
解决:这种场景是“事务开始 shared locks 产生到结束期间,shared locks 一直存在”
或 MVCC(后续有详细说明) 可以解决的。

-------------------------------------------------------------------------------------
第二种场景[second scenario] 事务内部或非内部完成另一个事务的[关于该事务search query的]insert
我们给事务加了 exlusive locks.
假设表中有zhang1,zhang2

事务内部完成另一个事务的[关于该事务search query的]insert
事务1:                                               |事务2
select * from student where name='zhang%'        |
//we get:{zhang1,zhang2}                         |
|start
|insert into  student(name) values(zhang3)
|other statements.
|commit
select * from student where name='zhang%'        |
//we get:{zhang1,zhang2,zhang3}                  |
other statements.                                |
commit                                           |
分析:
看到了么这里的事务1两次的结果分别为{zhang1,zhang2}和{zhang1,zhang2,zhang3},
这里后面无论事务2是否提交完成,只要 insert 这句statement完成,事务1的第二个查询就得到
{zhang1,zhang2,zhang3}的结果了。

事务非内部完成另一个事务的[关于该事务search query的]insert
事务1:                                               |事务2
select * from student where name='zhang%'        |
//we get:{zhang1,zhang2}                         |
|start
|insert into  student(name) values(zhang3)
select * from student where name='zhang%'        |
//we get:{zhang1,zhang2,zhang3}                  |
|other statements.
other statements.                                |commit
commit                                           |

这就是 phantom 现象。 phantom 现象说的就是鬼魅一样,事务中有两次search query,两次结果是不一样的。
phantom 现象
定义:
A phantom read occurs when, in the course of a transaction, two identical queries are
executed, and the collection of rows returned by the second query is different from the
first. The phantom reads anomaly is a special case of Non-repeatable reads
”phantom read“发生在一个事务中两个同样的查询,得到的行的集合的结果。两个结果集合不一致的情况。
”phantom read“ 现象也是特殊的nonrepeatable现象
原因:
事务中另一事务插入(关于该事务的search query的条件内的)数据。必须加range锁,即insert时候生成
exclusive locks并在事务完成后才释放。
解决:这种场景是“事务开始 shared locks 产生到结束期间,shared locks 一直存在”不可以解决的。
必须range locks or MVCC(后续有详细说明) 才可以解决的
-------------------------------------------------------------------------------------
phantom 现象
定义:
A phantom read occurs when, in the course of a transaction, two identical queries
are executed, and the collection of rows returned by the second query is different
from the first. The phantom reads anomaly is a special case of Non-repeatable reads
”phantom read“发生在一个事务中两个同样的查询,得到的行的集合的结果。两个结果集合不一致的情况。
”phantom read“ 现象也是特殊的nonrepeatable现象
原因:(以下条件之一就会造成phantom data)
1.事务内部完成另一个事务的(关于该事务的search query的)modify。“事务开始 shared locks
产生到结束期间,shared locks 一直存在”可以解决
2.事务中另一事务插入(关于该事务的search query的条件内的)数据。必须加range锁才可以解决。

2.2 事务开始 shared locks 产生到结束期间,shared locks 一直存在
(即 shared locks are held until the transaction completes.)
即对事务中已读的数据,在该事务结束之前,不允许其他事务去 modify(包括update,delete).
[特别注意]但是可以insert!

示例1: shared locks 是如何解决事务中已 read 的数据的 modify。
我们给事务加了 exlusive locks.
假设表中有zhang1,zhang2
事务1:                                         |事务2
start                                    |start
select * from student where name='zhang%'|
//we get:{zhang1,zhang2}                 |update student set name='abc' where name ='zhang%'(阻塞)
other statements.                        |
commit                                   |
|update student set name='abc' where name ='zhang%'(重新启动)
|other statements.
|commit

当执行事务1“select...”后,得到结果{zhangone,zhangtwo}两行并加shared lock,
这时候事务2开始,执行到“update...”时,阻塞。这句不能成功执行,
只能wait事务1把{zhangone,zhangtwo}shared locks释放后,事务2才能执行“update...”

示例2: shared locks 是如何挡不住事务中已 read 条件的范围内的 insert。
我们给事务加了 exlusive locks.
假设表中有zhang1,zhang2
事务1:                                        |事务2
start                                    |start
select * from student where name='zhang%'|
//we get:{zhang1,zhang2}                 |insert into  student(name) values(zhang3)
select * from student where name='zhang%'|other statements.
//we get:{zhang1,zhang2,zhang3}          |commit
other statements.                        |
commit                                   |

2.3 事务开始 range locks 产生到结束期间,range locks 一直存在?
range locks是给你select的条件里的情况都加锁,不允许该条件内的 [ update and insert ]。
定义:
Range locks are placed in the range of key values that match the search conditions of
each statement executed in a transaction. This blocks other transactions from updating
or inserting any rows that would qualify for any of the statements executed by the current
transaction.

Key-range locks protect a range of rows implicitly included in a record set being read by a Transact-SQL statement
while using the serializable transaction isolation level. The serializable isolation level requires that any query executed
during a transaction must obtain the same set of rows every time it is executed during the transaction. A key range lock
protects this requirement by preventing other transactions from inserting new rows whose keys would fall in the range
of keys read by the serializable transaction.

譬如事务中有"select * from student where name='zhang%' ",我们给事务加了range locks.
那么另个事务中你要insert一个学生名字等于zhang3都是不允许的.你要update zhang2为zhang22也是不允许的

示例:我们给事务加了 range locks.
事务1:                                         |事务2
start                                     |
select * from student where name='zhang%' |
//we get {zhang1,zhang2}                  |
|start
|insert into  student(name) values(zhang3)(被阻塞)
|or
|update student set name='abc' where name ='zhang%'(被阻塞)
other statements.                         |
commit                                    |
|insert into  student(name) values(zhang3)(重新启动)
|or
|update student set name='abc' where name ='zhang%'(重新启动)
|other statements.
|commit

三.事务隔离级别(TRANSACTION ISOLATION LEVEL)
SET TRANSACTION ISOLATION LEVEL
{ READ UNCOMMITTED
| READ COMMITTED
| REPEATABLE READ
| SNAPSHOT
| SERIALIZABLE
}
[ ; ]

设置和查看当前数据库isolation level的命令
//查看当前会话隔离级别
select @@tx_isolation;
//查看系统当前隔离级别
select @@global.tx_isolation;
//设置当前会话隔离级别
set session transaction isolation level repeatable read;
//1.read uncommitted 2.read committed  3.repeatable read(MySQL默认隔离级别)  4.serializable
//设置系统当前隔离级别
set global transaction isolation level repeatable read;

1.READ UNCOMMITTED
定义:
Specifies that statements can read rows that have been modified by other transactions
but not yet committed.
翻译:事务可以读其他事务中被更改还没有提交的数据。
缺点:所以我们会读到脏数据 dirty read.即未必会在数据库存在的数据,如果事务被rallback而没有commied的话

如果看成是锁实现的话:
“事务中exlusive locks产生到结束期间,exlusive locks 一直存在”    NO
“事务开始 shared locks 产生到结束期间,shared locks 一直存在”   NO
“事务开始 range locks 产生到结束期间,range locks 一直存在”   NO

示例1:不解决事务中已 modify 的数据的可读性的。 ------dirty read
假设表中有zhang1,zhang2
事务1:                                                |事务2
|start
start                                             |update student set name='abc' where name ='zhang%'
select * from student where name='zhang%'(不被阻塞)|
//we get:{}                                       |other statements.
|commit
|rallback //事实上表中还是有zhang1,zhang2
other statements.                                 |
commit                                            |

反例:事务中exlusive locks产生到结束期间,exlusive locks 一直存在 ------not dirty read
示例2:exclusive locks 是如何解决事务中已 modify 的数据的可读性的。
我们给事务加了 exlusive locks.
假设表中有zhang1,zhang2
事务1:                                               |事务2
|start
start                                            |update student set name='abc' where name ='zhang%'
select * from student where name='zhang%'(被阻塞) |
|other statements.
|commit
|rallback  //事实上表中还是有zhang1,zhang2
select * from student where name='zhang%'        |
//we get:{zhang1,zhang2}                         |
other statements.                                |
commit                                           |

2.READ COMMITTED
定义:
Specifies that statements cannot read data that has been modified but not committed
by other transactions.
翻译:事务不会读其他事务中更改但没有提交的数据

如果看成是锁实现的话:
“事务中exlusive locks产生到结束期间,exlusive locks 一直存在“   YES
“事务开始 shared locks 产生到结束期间,shared locks 一直存在”    NO
“事务开始 range locks 产生到结束期间,range locks 一直存在” NO
参照以上的“2.1 事务中exlusive locks产生到结束期间,exlusive locks 一直存在”

缺点:在事务中modify的数据不可读了.nonrepeatable reads or phantom date。
示例请看
"二.事务与锁"\"2. 锁在事务中一直存在的作用:"\"2.1 事务中exlusive locks产生到结束期间,exlusive locks 一直存在"
中三个示例

3.REPEATABLE READ
定义:Specifies that statements cannot read data that has been modified but not yet committed by
other transactions and that no other transactions can modify data that has been read by
the current transaction until the current transaction completes.
翻译:当前事务不能读其他事务中被更改的但未提交的数据。其他事务不能modify当前事务中的已读但未提交的数据。

如果看成是锁实现的话:
“事务中exlusive locks产生到结束期间,exlusive locks 一直存在“   YES
“事务开始 shared locks 产生到结束期间,shared locks 一直存在”    YES
“事务开始 range locks 产生到结束期间,range locks 一直存在”  NO
参照以上的“2.1 事务中exlusive locks产生到结束期间,exlusive locks 一直存在”
参照以上的“2.2 事务开始 shared locks 产生到结束期间,shared locks 一直存在”

缺点:phantom data。
示例请看
"二.事务与锁"\"2. 锁在事务中一直存在的作用:"\"2.1 事务中exlusive..."\
下的
"示例1:exclusive locks 是如何解决事务中已 modify 的数据的可读性的。"
"示例3:exclusive locks 是挡不住phantom data 的"\"第一种场景[first scenario] 事务内部完成另一个事务的
(关于该事务的search query的)modify"

"二.事务与锁"\"2. 锁在事务中一直存在的作用:"\"2.2 事务开始 shared locks ..."

4.SERIALIZABLE
定义:
Specifies that data read by any statement in a transaction will be the transactionally
consistent version of the data that existed at the start of the transaction
翻译:当前事务读的所有数据要与事务开始时候一致。

如果看成是锁实现的话:
“事务中exlusive locks产生到结束期间,exlusive locks 一直存在“   YES
“事务开始 shared locks 产生到结束期间,shared locks 一直存在”    YES
“事务开始 range locks 产生到结束期间,range locks 一直存在”  YES
这就解决了 phantom data
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: