Oracle数据库自动为事务锁定一个资源,以防止其他事务对相同资源进行独占访问。根据执行的操作和资源,数据库在不同的限制级别自动获取不同类型的锁。Oracle数据库的锁分为DML锁、DDL锁和System锁,下面将一一详细介绍:
DML Locks
DML锁,也称为数据锁,保证被多个用户并发防伪的数据的完整性。DML语句自动获得下面类型的锁:
- 行锁(Row Locks/TX)
- 表锁(Table Locks/TM)
行锁(TX)
行锁,也称为TX锁,是在表的单行上的锁。对每个insert、update、delete、merge或select … for update修改的语句,事务将会获取一个行锁。行锁在事务提交和回滚前一直存在。
行锁提供了一个队列机制,防止两个事务修改相同的行。数据库总是以排他模式锁定修改的行,因此在持有该锁的事务提交或回滚前,其他事务不能修改对应的行。行锁提供了最细粒度的锁定可能,因此提供了最佳的并发性和吞吐量。
如果因为实例故障一个事务中断,那么在整个事务恢复之前,先进行块级别的恢复使行可用。
如果事务获取一行的行锁,那么事务也获取了包含改行的表的锁,表锁防止在当前事务中覆盖数据更改的冲突DDL操作。
行锁和并发性
由于会话是隔离的,因此每个会话只能看到自己的未提交的更新,看不到其他会话所做的未提交的更新。数据库使用多版本读一致性显示每个会话更改前的内容。
行锁的存储
不像其他数据库,使用所管理器在内存中维护锁的列表。Oracle数据库使用包含被锁的行的数据块来存储锁信息。
数据库使用排队机制获取行锁,如果事务需要锁定未被锁定的行,那么事务将会在数据块中放置一个锁。通过该事务修改的每一行都指向存储在块头(block header)的事务ID的一个拷贝。
当事务结束时,事务ID仍在块头中,如果一个不同的事务想要修改一行,那么它使用事务ID来决定锁是否是活动状态。如果锁是活动的,那么当锁释放时,该会话被告知,否则,该事务获取锁。
表锁(TM)
表锁,也称为TM锁。当一个表通过insert、update、delete、merge,select … for update或lock table语句修改时,事务获取表锁。DML操作需要表锁来保留对表的DML访问,并防止和事务冲突的DDL操作。
表锁可以有以下模式:
- Row Share(RS):也称为subshare table lock(SS),表示在表上持有锁的事务已经锁定了表中的行,并打算更新它们。row share lock是表锁的最不受限制的模式,提供了表的最高程度的并发性;
- Row Exclusive Table Lock(RX):通常表示表上持有锁的事务已更新了表行或执行了select … for update语句。SX锁允许其他事务在同一张表同时进行查询、插入、删除或锁定行。因此,SX锁允许多个事务同时获得同一张表的SX和subshare table lock;
- Share Table Lock(S):事务持有的share table lock允许其他事务查询表(不使用select … for update),但是只有在单个事务持有share table lock时才允许更新。由于多个事务可能同时持有share table lock ,因此,持有此锁并不足以确保事务可以修改表;
- Share Row Exclusive Table Lock(SRX):也称为share-subexclusive table lock(SSX),比share table lock更严格。对于一个给定的表,一次只有一个事务可以获取SSX锁。事务持有的SSX锁允许其他事务查询表(select … for update 除外),但是不能更新表;
- Exclusive Table Lock(X):该锁最严格,禁止其他事务执行任何类型的DML语句或在表上设置任何类型的锁。
锁和外键
Oracle数据库最大限度地实现了对依赖外键的父键的并发控制。在heap-organized中,锁行为依赖于外键列的索引。如果外键没有建立索引,那么子表可能会更加频繁的锁住,死锁也会发生,并发性也会降低。基于这个原因,Oracle建议在大多数情况下索引外键,除非匹配的唯一键或主键从不会被更新和删除。
锁和没有索引的外键
如果满足下面的条件,数据库获得子表的全表锁:
- 子表的外键列没有索引;
- 一个会话修改了父表的主键,或merge行到主表。插入父表不会获得对子表的表锁;
锁和有索引的外键
如果满足下面的条件,数据库不会获得子表的全表锁:
- 子表上的外键列建立了索引;
- 一个会话修改了父表的主键,或merge行到主表。
在父表上的锁可以防止事务获取exclusive table lock,但是在主键更新的过程中,不能防止父表或子表上的DML操作。如果主键修改发生在父表,而更新发生在子表,则这种情况更可取。
DDL Locks
当正在进行的DDL操作对对象执行或引用时,ddl(data dictionary lock)锁保护schema对象的定义。在DDL操作期间,只有被修改或引用的单独的schema对象被锁定,数据库从不锁定整个数据字典。
Oracle数据库自动为需要它的任何DDL事务自动获取DDL锁。用户不能显式请求DDL锁。例如,如果一个用户创建了一个存储过程,那么Oracle数据库自动获取存储过程定义引用的所有schema对象的DDL锁,这些DDL锁防止存储过程编译完成前这些对象被修改或删除。
排它DDL锁
Exclusive DDL Lock防止其他会话获得DDL或DML锁。大多数DDL操作,除了下面描述的“Share DDL Locks”,需要exclusive lock防止那些可能修改或引用相同schema对象的其他DDL操作的破坏性干扰。例如,当ALTER table正在增加一列时,Drop table不允许删除表,反之亦然。
排它DDL锁在DDL语句执行和自动提交期间一直存在,在获取一个排它DDL锁时,如果另一个操作的schema对象持有DDL锁,那么该获取操作等待,直到之前的DDL锁释放,然后继续处理。
共享DDL锁
Share DDL Locks防止对有冲突的DDL操作的破坏性干扰,但允许相似DDL操作的数据并发。
例如,当运行create procedure语句时,包含的事务获取所有引用的表的共享DDL锁。其他事务可以同时创建引用相同的表的存储过程,并且同时获取这些表的共享DDL锁,但是任何事务都不能获取任何被引用的表的排它锁。
共享DDL锁在DDL语句执行和自动提交期间一直存在,因此,一个持有共享DDL锁的事务保证在事务过程中引用的schema对象的定义保持不变。
可中断解析锁
parse lock被SQL语句或它引用的每个schema对象的PL/sql程序单元持有。如果引用的对象被修改或删除,则获取parse lock以使相关联的shared SQL area无效。parse lock被称为breakable parse lock。
在SQL语句执行的解析阶段,在shared pool获取解析锁,只要该语句的共享SQL区保留在shared pool,就会一直持有parse lock 。
System Locks
Oracle数据库使用各种类型的系统锁来保护内部数据库和内存结构,用户无法访问这些机制,因为用户无法控制它们的发生和持续时间。
Latches
Latches是一种简单的、低级别的序列化机制,协调多用户访问共享数据结构、对象和文件。当多个进程访问时,Latches保护共享的内存资源免受损害。具体来说,latches保护数据结构不受下面情况的影响:
- 多个会话并发修改;
- 在被另一个会话修改时被一个会话读取;
- 被访问时内存重新分配(老化);
通常,单个latch保护SGA中的多个对象。例如,诸如DBWn和LGWR这样的后台进程从shared pool分配内存来创建数据结构,为分配此内存,这些进程使用shared pool latch来序列化访问,以防止两个进程试图同事检查或修改shared pool。内存被分配后,其他进程可能需要访问如库缓存(library cache,用来解析)这样的内存区域。在这种情况下,进程仅latch库缓存,而不是整个shared pool。
Mutexes
mutual exclusive object(mutex)是一种低级别的机制,它防止内存中的对象在被并发进程访问时过时或被破坏。mutex和latch相似,但是latch通常保护一组对象,而mutex保护单个对象。
mutex提供几个好处:
- mutex减少争用的可能性:由于latch保护多个对象,当进程同时访问这些对象时,它会成为一个瓶颈,通过序列化访问那个对象,而不是访问一个组,mutex增加了可用性;
- mutex比latch消耗更少的内存;
- 在共享模式下,mutex运行多个会话同事引用;
Internal Locks
内部锁是比latch和mutex更高级别的、更复杂的机制,服务于各种目的。数据库使用下面类型的内部锁:
- Dictionary cache locks:字典缓存锁持续时间很短,当条目(entries)被修改或使用时,该锁被字典缓存中的条目持有,它们保证被解析的语句不会看到不一致的对象定义。字典缓存锁可以是共享的或排它的,当解析完成时,共享锁被释放;而当DDL操作完成时排它锁被释放;
- File and log management locks:该锁保护各种文件,例如:一个内部锁保护控制文件,以便每次只有一个进程可以更改它,另一个锁协调在线重做日志文件的使用和归档。数据文件被锁定,以确保多个实例在共享模式下mount数据库,或者一个实例以排它模式mount数据库。由于文件和日志锁显示文件的状态,所以这些锁必须保持很长时间。
- Tablespace and undo segment locks:这些锁保护表空间和undo段。例如,访问数据库的所有实例必须同意表空间是联机或脱机。undo段被锁定,这样只有一个数据库实例可以写入一个段。
参考:官方文档