数据库中的事务需要满足四个基本特性:ACID,即原子性、一致性、隔离性和持久性。所谓隔离性即指多个并发的事务不应该相互影响,彼此对数据库元素的操作应该是透明的、不可见的,但在系统的实现中,很难完全保证事务的绝对隔离,根据事务之间对数据的可见性,可能出现一些现象(
phenomena ):
1)脏读(
dirty read):一个事务读取到另一个
未提交事务的数据;
2)不可重复读(
nonrepeatable read):在一个事务中,重复读取
同一条数据,发现数据被
已提交的事务修改;
3)幻读(
phantom read):在一个事务中,重复执行一条SQL语句返回的满足检索条件的元组已被其他
已提交的事务修改。
根据维基百科上的例子对以上三种现象进行详细说明:
users
id
|
name
|
age
|
1
|
Joe
|
20
|
2
|
Jill
|
25
|
脏读
Transaction 1
|
Transaction 2
|
/* 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 */
|
事务1在第二次执行Query1时读到了事务2更新过的元组,但随后事务2进行了回滚,这样就导致事务1为用户展现的结果是错误的,其本身并不存在,确切的说只在某个时间点存在过。
不可重复读
Transaction 1
|
Transaction 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 */
|
事务1在执行第一次Query 1之后,事务2对id=1的元组做了更新操作并提交,事务1再次执行Query 1时获取到的是同一条元组,但age却与第一次执行时不同。
幻读
Transaction 1
|
Transaction 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;
COMMIT;
|
事务1先后执行两次Query 1,将会得到不同的结果,只因事务2新添加了一条元组并提交。
不同的隔离级别则用于解决以上可能出现的问题,SQL标准提出的隔离级别如下:
Isolation Level
|
Dirty Read
|
Nonrepeatable Read
|
Phantom Read
|
Read uncommitted
|
Possible
|
Possible
|
Possible
|
Read committed
|
Not possible
|
Possible
|
Possible
|
Repeatable read
|
Not possible
|
Not possible
|
Possible
|
Serializable
|
Not possible
|
Not possible
|
Not possible
|
关于PostgreSQL的隔离级别后续再做介绍。
参考文献:
1.http://www.postgresql.org/docs/devel/static/transaction-iso.html
2.(database_systems)
阅读(2282) | 评论(0) | 转发(0) |