设为首页 加入收藏

TOP

事务隔离等级(二)
2014-11-24 03:07:30 】 浏览:173
Tags:事务 隔离 等级

/* Query 1 */

SELECT age FROM users WHERE id = 1;

/* will read 20 */

/* Query 2 */

UPDATE users SET age = 21 WHERE id = 1;

/* No commit here */

/* Query 1 */

SELECT age FROM users WHERE id = 1;

/* will read 21 */

ROLLBACK; /* lock-based DIRTY READ */

在这个例子中,事务2回滚后就没有id是1,age是21的数据行了。

不可重复读(non-repeatable read)

在一次事务中,当一行数据获取两遍得到不同的结果表示发生了“不可重复读(non-repeatableread)”.

在基于锁的并发控制中“不可重复读(non-repeatable read)”现象发生在当执行SELECT 操作时没有获得读锁(read locks)或者SELECT操作执行完后马上释放了读锁;多版本并发控制中当没有要求一个提交冲突的事务回滚也会发生“不可重复读(non-repeatable read)”现象。

事务 1

事务 2

/* Query 1 */

SELECT * FROM users WHERE id = 1;

/* Query 2 */

UPDATE users SET age = 21 WHERE id = 1;

COMMIT; /* in multiversion concurrency

control, or lock-based READ COMMITTED */

/* Query 1 */

SELECT * FROM users WHERE id = 1;

COMMIT; /* lock-based REPEATABLE READ */

在这个例子中,事务2提交成功,因此他对id为1的行的修改就对其他事务可见了。但是事务1在此前已经从这行读到了另外一个“age”的值。在可序列化 (SERIALIZABLE)和可重复读(REPEATABLE READS)的隔离级别,数据库在第二次SELECT请求的时候应该返回事务2更新之前的值。在授权读(READ COMMITTED)和未授权读(READ UNCOMMITTED),返回的是更新之后的值,这个现象就是不可重复读(non-repeatableread)。

有两种策略可以避免不可重复读(non-repeatable read)。一个是要求事务2延迟到事务1提交或者回滚之后再执行。这种方式实现了T1,T2 的串行化调度。串行化调度可以支持可重复读(repeatablereads)。

另一种策略是多版本并发控制。为了得到更好的并发性能,允许事务2先提交。但因为事务1在事务2之前开始,事务1必须在其开始执行时间点的数据库的快照上面操作。当事务1最终提交时候,数据库会检查其结果是否等价于T1, T2串行调度。如果等价,则允许事务1提交,如果不等价,事务1需要回滚并抛出个串行化失败的错误。

使用基于锁的并发控制,在可重复读(REPEATABLE READS)的隔离级别中,ID=1的行会被锁住,在事务1提交或回滚前一直阻塞语句2的执行。在授权读(READ COMMITTED)的级别,语句1第二次执行,age已经被修改了。

在多版本并发控制机制下,可序列化(SERIALIZABLE)级别,两次SELECT语句读到的数据都是事务1开始的快照,因此返回同样的数据。但是,如果事务1试图UPDATE这行数据,事务1会被要求回滚并抛出一个串行化失败的错误。

在授权读(READ COMMITTED)隔离级别,每个语句读到的是语句执行前的快照,因此读到更新前后不同的值。在这种级别不会有串行化的错误(因为这种级别不要求串行化),事务1也不要求重试。

幻影读(phantom read)

在事务执行过程中,当两个完全相同的查询语句执行得到不同的结果集。这种现象称为“幻影读(phantom read)”

当事务没有获取范围锁的情况下执行SELECT ... WHERE操作可能会发生“幻影读(phantom read)”。

“幻影读(phantom read)”是不可重复读(Non-repeatable reads)的一种特殊场景:当事务1两次执行SELECT ... WHERE检索一定范围内数据的操作中间,事务2在这个表中创建了(如INSERT)了一行新数据,这条新数据正好满足事务1的“WHERE”子句。

事务 1

事务 2

/* Query 1 */

SELECT * FROM users

WHERE age BETWEEN 10 AND 30;

/* Query 2 */

INSERT INTO users VALUES ( 3, 'Bob', 27 );

COMMIT;

/* Query 1 */

SELECT * FROM users

WHERE age BETWEEN 10 AND 30;

需要指出的是事务1执行了两遍同样的查询语句。如果设了最高的隔离级别,两次会得到同样的结果集,这也正是可数据库在序列化(SERIALIZABLE)隔离级别上需要满足的。但是在较低的隔离级别上,第二次查询可能会得到不同的结果集。

在可序列化(SERIALIZABLE)隔离级别,查询语句1在age从10到30的记录上加锁,事务2只能阻塞直至事务1提交。在可重复读(REPEATABLEREAD)级别,这个范围不会被锁定,允许记录插入,因此第二次执行语句1的结果中会包括新插入的行。

隔离级别、读现象和锁(Isolation Levels, ReadPhenomena and Locks)

隔离级别vs读现象(IsolationLevels vs Read Phenomena)

隔离级别

脏读

不可重复读

幻影读

未授权读

可能发生

可能发生

可能发生

授权读

-

可能发生

可能发生

可重复读

-

-

可能发生

可序列化

-

-

-

可序列化(Serializable)隔离级别不等同于可串行化(Serializable)。可串行化调度(Serializable)是避免以上三种现象的必要条件,但不是充分条件。

“可能发生”表示这个隔离级别会发生对应的现象,“-”表示不会发生。

隔离级别vs 锁持续时间(IsolationLevels vs Lock Duration)

在基于锁的并发控制中,隔离级别决定了锁的持有时间。"C"-表示锁会持续到事务提交。 "S" –表示锁持续到当前语句执行完毕。如果锁在语句执行完毕就释放则另外一个事务就可以在这个事务提交前修改锁定的数据,从而造成混乱。

隔离级别l

写操作

读操作

范围操作 (...where...)

未授权读

S

S

S

授权读

C

S

S

可重复读

C

C

S

可序列化

C

C

C

参照

相关条目

原子性一致性持久性锁乐观并发控制关系数据库快照隔离

外部链接

Oracle Database Concepts,chapter 13 Data Concurrency and Consistency, Preventable Phenomena and Transaction Isolation LevelsOracle Database SQL Reference,chapter 19 SQL Statements: SAVEPOINT to UPDA

首页 上一页 1 2 3 下一页 尾页 2/3/3
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇如何用Java将excel数据导入数据库 下一篇MongoDB:mongodb的主从复制(一)

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目