事务
转载自:http://blog.csdn.net/jiyiqinlovexx/article/details/50967965
引言:在网上搜了很多关于事务的文章,感觉单独来看都很难看懂,所以综合自己的理解写一篇我自己能理解的关于关系型数据库事务的文章。
一、事务特征
我们都知道数据库事务具备ACID特性:
Atomic(原子性):一个事务要么成功,要么失败
Consistency(一致性):一致性代表了底层数据存储的完整性。事务执行前后数据库都必须处于一个合法的状态。什么才是一个合法的状态?
比如满足数据库的唯一性约束、数据类型验证、引用完整性等,更复杂的还包括事务执行后结果不会和现实业务期望的结果不同。
举个例子:比如由两张表学生表和专业表,因为学生要有一个所属的专业,所以学生表需要引用专业表,但是如果新增一个专业和一个学生,而这个学生恰好属于这个新专业,那么这两个插入操作必须放在一个事务中如果有一个失败都要回滚,不然就会导致学生可能引用一个不存在的专业,出现事务执行后数据库引用不完整。
另外比如银行系统有多个账户,钱只会在账户之间相互转移,而不会凭空消失,如果要将账户A的钱转移到账户B,那么账户A的扣钱操作比如和账户B的加钱操作要么一起成功,要么一起失败,保证事务执行前后业务数据都处于一致的状态。
Isolation(隔离性):隔离性意味着事务必须在不干扰其他进程或事务的前提下独立执行
Durability(持久性):事务结束后,事务处理的结果必须能够得到固化。
二、问题
如果没有任何并发控制机制,不同的线程执行事务时会出现几类问题:
1.更新丢失
(1)更新丢失(Lostupdate)
两个事务同时更新,第二个事务回滚会覆盖第一个事务更新的数据,导致更新丢失
(2)两次更新问题(Secondlost updates problem)
两个事务都读取了数据,并同时更新,第一个事务更新失败,因为被第二个事务覆盖。
2.脏读(Dirty Reads)
事务T1读取到事务T2修改了但是还未提交的数据,之后事务T2又回滚其更新操作,导致事务T1读到的是脏数据。
3.不可重复读(Non-repeatableReads)
事务T1读取某一行数据后,事务T2对其做了修改,当事务T1再次读该数据时得到与前一次不同的值。
4.幻读(Phantom Reads)
事务T1读取在读取范围数据时,事务T2又插入一条数据,当事务T1再次数据这个范围数据时发现不一样了,出现了一些“幻影行”。
三、并发控制
为此我们需要通过提供不同类型的“锁”机制针对数据库事务进行不同程度的并发访问控制,由此产生了不同的事务隔离级别:隔离级别(低->高)
●读未提交(Read Uncommitted)
含义解释:只限制同一数据写事务禁止其他写事务。解决”更新丢失”
名称解释:可读取未提交数据
所需的锁:排他写锁
●读提交(Read Committed)
含义解释:只限制同一数据写事务禁止其它读写事务。解决”脏读”,以及”更新丢失”
名称解释:必须提交以后的数据才能被读取
所需的锁:排他写锁、瞬间共享读锁
●可重复读(Repeatable Read)
含义解释:限制同一数据写事务禁止其他读写事务,读事务禁止其它写事务(允许读)。解决”不可重复读”,以及”更新丢失”和”脏读”。
注意没有解决幻读,解决幻读的方法是增加范围锁(range lock)或者表锁。
名称解释:能够重复读取
所需的锁:排他写锁、共享读锁
●序列化(Serializable)
提供严格的事务隔离。它要求事务序列化执行,事务只能一个接着一个地执行,但不能并发执行。如果仅仅通过“行级锁”是无法实现事务序列化的,必须通过其他机制保证新插入的数据不会被刚执行查询操作的事务访问到。
限制所有读写事务都必须串行化实行。
下表是各隔离级别对各种异常的控制能力。
|
更新丢失 |
脏读 |
不可重复读 |
幻读 |
RU(读未提交) |
避免 |
|
|
|
RC(读提交) |
避免 |
避免 |
|
|
RR(可重复读) |
避免 |
避免 |
避免 |
|
S(序列化) |
避免 |
避免 |
避免 |
避免 |
四、常用数据库默认隔离级别
各类数据库默认事务隔离级别
数据库 |
默认级别 |
MySQL |
可重复读(Repeatable Read) |
Oracle |
读提交(Read Committed) |
SQLServer |
读提交(Read Committed) |
DB2 |
读提交(Read Committed) |
PostgreSQL |
读提交(Read Committed) |