事务的特性(ACID)
- 原子性:事务是一个完整的操作。
- 一致性:事务完成时数据必须处于一致状态
- 隔离性:对数据进行修改的所有并发事务是彼此隔离的,这表明事务必须是独立的,它不应以任何方式依赖于或影响其他事务。
- 永久性:事务完成后,它对数据库的修改被永久保持,事务日志能够保持事务的永久性。
需要并发控制的原因
丢失更新(更新被破坏导致)
- 当两个事务Tran1和Tran2同事更新某条记录是,他们读入并修改记录,出现事务Trans2提交的结果破坏了事务Tran1提交的结果的情况,导致Tran1的修改结果丢失,因此出现“丢失更新”的问题。
“脏”数据(数据回滚导致)
- “脏”数据是指事务Tran1修改某一条记录,并将其写入数据库,事务Tran2读取同一条记录后,事务Tran1由于某种原因被回滚取消,此时被事务Tran1修改过的数据恢复原值,事务Tran2读取到的数据就与数据库中的数据不一致了,该数据称为“脏”数据。
不可重复读取(更新导致)
- “不可重复读取”也称为“不一致的分析”,是指事务Tran1读取数据后。事务Tran2对同一数据执行更新操作,使得Tran1再次读取该数据时得到与之不同的值。
幻影数据(插入数据或删除数据导致)
- 事务Tran1按一定的条件从数据库等集合中读取数据后,事务Tran2对该数据集删除或插入了一些记录,当事务Tran1按相同条件读取数据时,发现少了或者多了一些记录。
封锁协议
一级封锁协议
- 任何尝试更新记录Record的事务必须对该Record加独占排他锁,并保持锁到事务结束,否则该事务进入等待队列,状态转换为等待,直到获得锁为止。这样就可以防止“丢失更新”和由于某些原因导致事务撤销造成的读“脏”数据的情况。
二级封锁协议
- 任何试图读取记录Record的事务必须对该Record加共享锁,读完后随即释放锁。当事务进一步进行更新Record操作时,将共享锁升级为独占排他锁,并一直保持到事务结束。这样提高了事务的并行度,解决了“丢失更新”和读“脏”数据的问题。
三级封锁协议
- 任何尝试读取记录Record的事务必须对Record加共享锁,直到该事务结束才释放。这样既可以防止“丢失更新”和读“脏”数据,还性进一步防止了“不可重复读取”,但同时会因为锁时间较长而易引发更多的死锁。
基本的锁类型
排他锁(又叫写锁)(X锁)
- 如果事务Tran对数据对象Record加上排他锁WriteLock,则只允许该Tran读取和修改Record,其他的任何事务都不能再对该Record加任何类型的锁,直到Tran释放该Record上的排他锁WriteLock为止。这就保证了在Tran释放对该Record的封锁之前,其他事务不能同时读取和修改此Record。可以避免丢失更新和脏数据。
- oracle中——可通过lock table in exclusive mode命令添加X锁。在该锁定模式下,其他用户不能对表进行任何的DML和DDL操作。
- 如果某事务获得了数据项A上的排他锁,则其他事务对数据项A 不能读也不能写
- 表级排它锁其他能不能读???
共享锁(又叫读锁--全部人读完才能改)(S锁)
- 如果事务Tran对数据对象Record加共享锁ReadLock,则其他事务也可以对该Record加共享锁ReadLock,但不能同时对该Record加排他锁WriteLock,直到该Record上的所有共享锁释放为止。所以,共享锁能够阻止对已加锁的数据进行更新操作。
- 使用共享锁,主要防止事务在读操作期间发生对数据的修改操作,因此允许其他事务对数据对象Record加共享锁ReadLock,完成对该数据对象的并行读取操作。但这降低了并发性。
- 事务Tran1在进行检索之前先对该表加共享锁,那么Tran1结束前,Tran2不能够获得该表的排他锁,即不能插入或者修改表记录。在Tran1完成本次检索统计操作之后,事务Tran1结束,这时Tran2才能够插入或修改表记录,避免了“幻影数据”。
- oracle中——可通过lock table in share mode命令添加该S锁。在该锁定模式下,不允许任何用户更新表。但是允许其他用户发出select …from for update命令对表添加RS锁。
锁有“共享锁”、“排它锁”,“共享排它锁”等多种类型,而且每种类型又行级锁 (一次锁住一条记录),页级锁 (一次锁住一页,即数据库中存储记录的最小可分配单元),表级锁 (锁住整个表)。
行级共享锁(RS锁)
- 通常是通过select … from for update语句添加的,同时该方法也是我们用来手工锁定某些记录的主要方法。比如,当我们在查询某些记录的过程中,不希望其他用户对查询的记录进行更新操作,则可以发出这样的语句。当数据使用完毕以后,直接发出rollback命令将锁定解除。当表上添加了RS锁定以后,不允许其他事务对相同的表添加排他锁,但是允许其他的事务通过DML语句或lock命令锁定相同表里的其他数据行。
行级排他锁(RX锁)
- 当进行DML操作时会自动在被更新的表上添加RX锁,或者也可以通过执行lock命令显式的在表上添加RX锁。在该锁定模式下,允许其他的事务通过DML语句修改相同表里的其他数据行,或通过lock命令对相同表添加RX锁定,但是不允许其他事务对相同的表添加排他锁(X锁)。
共享行级排他锁(SRX锁)
- 通过lock table in share row exclusive mode命令添加SRX锁。该锁定模式比行级排他锁和共享锁的级别都要高,这时不能对相同的表进行DML操作,也不能添加共享锁。
下图列出产生锁定模式的SQL语句:

事务隔离级别
- 设置事务隔离级别
设置事务隔离级也可以保证一个事务的执行不受其他事务的干扰,但设置事务隔离级别会话中的所有SQL语句加默认的锁。
描述 | 说明 |
---|---|
READ UNCOMMITTED | 该级别不发出共享锁和排他锁。当使用该选项是,既允许在事务结束前更改数据内的数值,行也可以出现在数据中或从数据集消失。这是4个隔离级别中限制最小的级别。 |
READ COMMITTED | 该级别是oracle默认的事务隔离级。它指定在读取数据时使用共享锁,但不要求在一个事务读取一条记录的间隙,其他事务不能对该记录进行更新。 |
REPETABLE READ | 严格的查询锁,锁定查询中使用的所有数据,以避免其他用户更新这些数据,并要求在一个事务读取同一条记录的间隙,其他事务不能对该记录进行更新。 |
SERIALIZABLE | 数据集(表)上的共享锁,直到该事务完成,才允许其他事务更新数据集或将记录插入到数据集。这是4个隔离级别中限制最高的级别,此并发级别比较低,只在必要时使用。 |
- 事务隔离级别允许不同类型的行为
隔离级别 | 脏数据 | 丢失更新 | 不可重复读 | 幻影数据 |
---|---|---|---|---|
READ UNCOMMITTED | YES | YES | YES | YES |
READ COMMITTED | NO | YES | YES | YES |
REPETABLE READ | NO | NO | NO | YES |
SERIALIZABLE | NO | NO | NO | NO |
采用默认的READ COMMITTED隔离级别能保证两个事务使用一个UPDATE语句更新行,并且不基于以前检索的值进行更新时不会发生丢失更新的问题。但当两个事务检索相同的行,然后基于原检索的值对行进行更新时会发生丢失更新的问题。
网友评论