日期:2014-05-16  浏览次数:20771 次

数据库 事务的隔离级别

数据库事务必须具备ACID特性,ACID是Atomic(原子性)、Consistency(一致性)、Isolation(隔离性)和Durability(持久性)的英文缩写。

    原子性:指整个数据库事务是不可分割的工作单位。只有使据库中所有的操作执行成功,才算整个事务成功;事务中任何一个SQL语句执行失败,那么已经执行成功的SQL语句也必须撤销,数据库状态应该退回到执行事务前的状态。

    一致性:指数据库事务不能破坏关系数据的完成性以及业务逻辑上的一致性。例如对银行转帐事务,不管事务成功还是失败,应该保证事务结束后ACCOUNTS表中Tom和Jack的存款总额为2000元。

    隔离性:指的是在并发环境中,当不同的事务同时操纵相同的数据时,每个事务都有各自的完整数据空间。

    持久性:指的是只要事务成功结束,它对数据库所做的更新就必须永久保存下来。即使发生系统崩溃,重新启动数据库系统后,数据库还能恢复到事务成功结束时的状态。


事务的(ACID)特性是由关系数据库管理系统(RDBMS,数据库系统)来实现的。数据库管理系统采用日志来保证事务的原子性、一致性和持久性。日志记
录了事务对数据库所做的更新,如果某个事务在执行过程中发生错误,就可以根据日志,撤销事务对数据库已做的更新,使数据库退回到执行事务前的初始状态。



数据库管理系统采用锁机制来实现事务的隔离性。当多个事务同时更新数据库中相同的数据时,只允许持有锁的事务能更新该数据,其他事务必须等待,直到前一个事务释放了锁,其他事务才有机会更新该数据。

?

?

?

?

?

数据库系统有四个隔离级别。对数据库使用何种隔离级别要审慎分析,因为

1. 维护一个最高的隔离级别虽然会防止数据的出错,但是却导致了并行度的损失,以及导致死锁出现的可能性增加。

2. 然而,降低隔离级别,却会引起一些难以发现的bug。

?

SERIALIZABLE(序列化)

?

添加范围锁(比如表锁,页锁等,关于range lock,我也没有很深入的研究),直到transaction A结束。以此阻止其它trasaction B对此范围内的insert,update等操作。

?

幻读,脏读,不可重复读等问题都不会发生。

?

REPEATABLE READ(可重复读)

?

对于读出的记录,添加共享锁直到transaction A结束。其它transaction B对这个记录的试图修改会一直等待直到trasaction A结束。InnoDB默认级别。

?

可能发生的问题:当执行一个范围查询时,可能会发生幻读。

?

READ COMMITTED(提交读)

?

在trasaction A中读取数据时对记录添加共享锁,但读取结束立即释放。其它transaction B对这个记录的试图修改会一直等待直到A中的读取过程结束,而不需要整个trasaction A的结束。所以,在trasaction A的不同阶段对同一记录的读取结果可能是不同的。

?

可能发生的问题:不可重复读。

?

READ UNCOMMITTED(未提交读)

?

不添加共享锁。所以其它trasaction B可以在trasaction A对记录的读取过程中修改同一记录,可能会导致A读取的数据是一个被破坏的或者说不完整不正确的数据。

?

另外,在trasaction A中可以读取到trasaction B(未提交)中修改的数据。比如trasaction B对R记录修改了,但未提交。此时,在Trasaction A中读取R记录,读出的是被B修改过的数据。

?

可能发生的问题:脏读。

?

?

MySql中设置隔离级别

?

查看InnoDB系统级别的事务隔离级别:

mysql> SELECT @@global.tx_isolation;
+-----------------------+
| @@global.tx_isolation |
+-----------------------+
| REPEATABLE-READ |
+-----------------------+
1 row in set (0.00 sec)

查看InnoDB会话级别的事务隔离级别:

mysql> SELECT @@tx_isolation;
+-----------------+
| @@tx_isolation |
+-----------------+
| REPEATABLE-READ |
+-----------------+
1 row in set (0.00 sec)

修改事务隔离级别:

mysql> set global transaction isolation level read committed;
Query OK, 0 rows affected (0.00 sec)

mysql> set session transaction isolation level read committed;
Query OK, 0 rows affected (0.00 sec)

InnoDB的可重复读隔离级别和其他数据库的可重复读是有区别的,不会造成幻象读(phantom read),所谓幻象读,就是同一个事务内,多次select,可以读取到其他session insert并已经commit的数据。下面是一个小的测试,证明InnoDB的可重复读隔离级别不会造成幻象读。测试涉及两个session,分别为 session 1和session 2,隔离级别都是repeateable read,关闭autocommit

mysql> select @@tx_isolation;
+-----------------+
| @@tx_isolation |
+-----------------+
| REPEATABLE-READ |
+-----------------+
1 row in set (0.00 sec)

mysql> set autocommit=off;
Query OK, 0 rows affected (0.00 sec)

session 1 创建表并插入测试数据

mysql> create table test(i int) engine=innodb;
Query OK, 0 rows affected (0.00 sec)

mysql> insert into test values(1);
Query OK, 1 row affected (0.00 sec)

session 2 查询,没有数据,正常,session1没有提交,不允许脏读

mysql> select * from test;
Empty set (0.00 sec)