又看了一遍oracel文档中concept的lock说明,基本上lock的概念理解的有些条理了..
- Concept
- 锁定机制:锁是并发访问的时候用于保护共享资源不被同时并发修改. 信息的完整性(integrity).
行级别的锁(TX),oracle提供的是non-escalate(非升级)的,其他的数据库escalate lock要么覆盖所有行甚至整个表(需要额外的资源去管理lock). Oracle只锁住要修改的行-允许更多的并发访问,冲突最小;而且因为oracle的锁信息是和行一起存储的,所以oracle可以锁定无限的行而无需用户进行任何没必要的等待. - 自动锁:用户无须干预,oracle server自动获得锁当sql语句执行的时候.
锁的类型或模式(mode)包括排他锁(exclusive)和共享(share)锁.级别有表级,行级.无论排他还是共享,query都可以继续运行. - 手动锁:用户也可以手动锁定,在行级(?select for update?)或者表级.
- 锁定周期(duration):
- 锁的持有周期到事务的结束.注意savepoint点的概念,如果rollback到savepoint点,那原来该点之后的修改所持有的锁被释放.(因为做了部分rollback嘛)
- 锁的转换(conversion)和升级(escalation)
- 锁转换: (是说锁的Level或degree的改变) 在行级别,如果一个事务持有了排他的行锁,则已经是最高限制了,所以锁不会进行其他转换了. 但在表级别,如果开始持有的是低级别的锁,则有可能在继续使用的过程中根据需要会自动转换成高级别的锁.比如:
先看看v$lock的lock mode说明:
Lock mode in which the session holds the lock:- 0 - none
- 1 - null (NULL)
- 2 - row-S (SS)
- 3 - row-X (SX)
- 4 - share (S)
- 5 - S/Row-X (SSX)
- 6 - exclusive (X)
- 锁转换: (是说锁的Level或degree的改变) 在行级别,如果一个事务持有了排他的行锁,则已经是最高限制了,所以锁不会进行其他转换了. 但在表级别,如果开始持有的是低级别的锁,则有可能在继续使用的过程中根据需要会自动转换成高级别的锁.比如:
- 锁定机制:锁是并发访问的时候用于保护共享资源不被同时并发修改. 信息的完整性(integrity).
U1 用户 session1:
SQL> update emp set sal=sal+10 where job='CLERK';
4 rows updated.
然后查看锁的使用情况:
select username,v$lock.sid,v$lock.TYPE,
trunc(id1/power(2,16)) rbs,
bitand(id1,to_number('ffff','xxxx'))+0 slot,
id2 seq,
lmode,
request
from v$lock, v$session
where v$lock.sid = v$session.sid
and v$session.username = 'U1';
| USERNAME | SID | TYPE | RBS | SLOT | SEQ | LMODE | REQUEST |
1 | U1 | 153 | TM | 0 | 53223 | 0 | 3 | 0 |
2 | U1 | 153 | TX | 7 | 15 | 480 | 6 | 0 |
正常update..拿到的是行的排他锁(TX 6-exclusive)和表上的共享锁(TM 3-SX)
如果select * from emp where job='CLERK' for update;
看到的锁是一致的
然后concept上说如果此时真的更新了部分行, update, 则TM的锁会转化为5. 但是试验中否定的了这种情况,是concept错了还是我错了????
- 锁升级:是说锁的level of granularity(粒度)的改变,比如,原来是行级别的,现在是表级别的. 比如某些数据库,当修改错误更改了表中的大部分数据的时候,会自动升级(escalate)行锁为表锁. 锁的使用数量是降低了,但锁的限制增加了. oracle从来不会如此因为其独特的锁定机制.
- 死锁:两个或者更多的会话彼此等待对方持有的锁就会产生死锁.例子略,concept上说明很清晰.
死锁检测: oracle会自动检测,并自动回滚产生死锁前的最后一个会话的sql语句.
死锁常发生在 用户显性(explicitly or manully)使用了锁,而不是隐形让oracle自动管理.
oracle死锁不常发生:因为, 1)no lock escalation,用啥锁啥,而且尽量low level 2)查询时不需read lock 3)row-lock而不是page-lock等其他的 …
避免死锁:定义好规则,多个事务按照相同的顺序访问表和数据. 比如master和detail表,先锁master表,然后锁detail,就不会出现问题.--开发过程中定义规则. 当你清楚的知道自己要陆续获得多个锁的时候,一个建议就是先获得最严格的锁(level高的),比如exclusive. - 锁的类型
- dml锁(数据锁):保护数据. 分不同的粒度级别,比如,table lock表锁锁住整个表(防止ddl破坏结构),行锁锁住选定的行(防止其他dml同时更改数据).一个DML语句必须同时获得这两种锁,
- DDL锁(数据字典锁--可不是表锁,表锁是DML锁的一种):保护对象结构.
- Intenal lock and latch.
- DML锁
- TX行锁:finest grain locking to give more concurrency and throughput. No escalation so will not to a coarser granularity.
- 在TX锁中,reader和writer的关系,对于相同的数据,不同的会话中,读不会等写,写也不会等读(除非select … for update),写只会等相同数据的其他写.
行锁是exclusive,对于insert,update,delete和select … for update.
- 在TX锁中,reader和writer的关系,对于相同的数据,不同的会话中,读不会等写,写也不会等读(除非select … for update),写只会等相同数据的其他写.
- TM表锁:阻止表被其他ddl修改. DML语句和DDL语句都需要持有TM锁,当然持有的level会有所区别. 同一个对象上的表锁有很多level,比如share和exclusive, exclusive level高,share低.
比如会话A先拿到了表share锁,则其他会话不可以获得高级别锁比如exclusive锁.
再如会话A先拿到了表exclusive锁,则其他会话什么其他锁也无法继续获得.
DML操作insert,update ,delete, 还有select…for update,以及ddl语句,还有lock,需要获得TM锁. DDL通常需要获得最高级别的exclusive TM lock.
表锁的级别:2 row share (RS), 3 row exclusive (RX), 4 share (S), 5 share row exclusive (SRX), 6 exclusive (X).
表锁的规则:
- TX行锁:finest grain locking to give more concurrency and throughput. No escalation so will not to a coarser granularity.
Table 13-3 Summary of Table Locks
1 | 2 | 3 | 4 | 5 | 6 | 7 |
SQL Statement | Mode of Table Lock | RS(2) | RX(3) | S(4) | SRX(5) | X(6) |
SELECT...FROM table... | none | Y | Y | Y | Y | Y |
INSERT INTO table ... | RX(3) | Y | Y | N | N | N |
UPDATE table ... | RX(3) | Y* | Y* | N | N | N |
DELETE FROM table ... | RX(3) | Y* | Y* | N | N | N |
SELECT ... FROM table FOR UPDATE OF ... | RS(2) | Y* | Y* | Y* | Y* | N |
LOCK TABLE table IN ROW SHARE MODE | RS(2) | Y | Y | Y | Y | N |
LOCK TABLE table IN ROW EXCLUSIVE MODE | RX(3) | Y | Y | N | N | N |
LOCK TABLE table IN SHARE MODE | S(4) | Y | N | Y | N | N |
LOCK TABLE table IN SHARE ROW EXCLUSIVE MODE | SRX | Y | N | N | N | N |
LOCK TABLE table IN EXCLUSIVE MODE | X | N | N | N | N | N |
1列代表sql语句的类型,2列是如果可以的话,可以获得的TM锁的类型.3,4,5,6,7列代表,此时其他会话是否可以获得其他类型的TM锁.
Y*代表如果没有其他冲突的被其他事务持有的行锁,则可以获得,否则就等待.
下面具体来说明
1 RS : 2 row share table lock(有时候也称subshare table, SS), 如果用户持有锁的表上已经锁定了行,现在没有修改,以后可能修改数据.
Select … for update, lock table in row share mode;--->但是我做实验的时候为什么select … for update总是取得的是 RX锁呢?
Session1(153):select * from emp where job='CLERK' for update;
Session2(148):lock table emp in row exclusive mode;
Session3(143):lock table emp in exclusive mode;
Session4:drop table emp;
会话3会阻塞等待(lock命令不是ddl命令,其实相当于dml,所以会开启一个新的事务). 因为被153和148会话阻塞.
会话4立即报错退出(不确认),因为ddl指令默认情况下不同于DML,DML遇到申请的资源被阻塞的时候会等待,而DDL会报错退出(nowait).(受参数ddl_wait_for_locks控制,但是10G中该参数已经失去作用,试验中无法验证),这其实也是oracle比较合理的策略,因为ddl要取得tm上的exclusive锁,这种高级别的锁持有的时间越短越好;申请也是如此,ddl执行的时间一般很短,如果申请不到,还在等待的话,其他会话申请TM锁还有意义嘛?而且如果结构修改了,则其他dml的语句应该重新parse..
另外,在一个事务内,获得了高级别锁后,仍然在该事务中可以获得<=该级别的锁(虽然没意义),但是如果想申请更高级别的锁,那就得看那种锁申请的条件了. 但是即使该事务获得了多种TM锁,数据库只按照中间获得的最高级别锁来处理(比如先后拿到表的65432,则只显示6最高级别的锁).
锁的情况:
| USERNAME | SID | TYPE | RBS | SLOT | SEQ | LMODE | REQUEST |
1 | U1 | 153 | TM | 0 | 53223 | 0 | 3 | 0 |
2 | U1 | 143 | TM | 0 | 53223 | 0 | 0 | 6 |
3 | U1 | 148 | TM | 0 | 53223 | 0 | 3 | 0 |
4 | U1 | 153 | TX | 4 | 24 | 469 | 6 | 0 |
10G帮助文件中参数描述的查询方法:reference-->instance parameter
与锁相关的几个参数,dml_locks,enqueue_resources,ddl_wait_for_locks:--10g文档已经查不到后面两个参数的说明了,是不是已经过期了.
2 RX: row exclusive table lock:3 又成SX(subexclusive table lock): dml时候最常用到的TM锁. 允许…,禁止(4,5,6的锁,比这个高的)
为啥教row exclusive table lock,以前常错误的理解为这个就是该行上的排他锁,当然是错误的,因为这个是在表上获得的锁,是修改表记录内容的时候,是要执行锁定部分row ,不过在表上也要拿到锁,当然叫这个名字很合适了,row exclusive的时候拿到的表锁:row exclusive table lock
3 S: share table lock 4
Lock table xxx in share mode; 或者在表上创建索引的时候自动获得该锁.
允许: select for update(RS), lock table share. 其他禁止(禁止dml)
同样,该试验失败. 因为select for update我在10g中获得的总是需要获得3 RX,而在规则中,有了4,则不可以获得3有冲突,所以实际试验中,select for update 处于等待状态.
4 share row exclusive table lock(SRX) 5:
只允许查询或者RS锁. RS锁即select for update(又试验失败,因为申请的是RX).
5 exclusive table lock(X) 6
只允许其他用户查询.最严格的锁.
- 总结一下
查询是不需要获得数据锁的,也不需要获得表锁.所以oracle的查询也称为nonblocking query. 自然也不需要等待任何其他操作. (如果查询的过程中有相关的ddl操作,则处理机制跟dml类似,因为回滚段会存放相关的内容,如果回滚段内容没了,error: snapshot too old).
DML…重复太多了:)4句
- DDL锁
- DDL锁保护在一个正在进行的DDL语句执行期间,其操作或者引用的对象的定义不被修改或删除.
用户不可以显性(手工)获得ddl锁,只能是自动获得的.同样,oracle只锁住需要锁的对象,减少冲突的发生可能性,增加并发性.
DDL这里是代表data dictionary lock,可不是数据定义语言的缩写:) - 三种类型
1 Exclusive ddl lock:
大多数ddl操作需要这种锁(alter,drop.truncate对象),排他的DDL锁会阻止其他的DDL操作在相同的对象上并行执行.
如果申请ddl锁的过程中,其他ddl语句已经持有锁,则该事务会等待. ---concept文档该位置又出现问题,不会等待,nowait报错退出.
DDL操作除了该锁外,也需要要修改对象的DML锁(data lock).
例子:删除列的时候获得锁
- DDL锁保护在一个正在进行的DDL语句执行期间,其操作或者引用的对象的定义不被修改或删除.
| USERNAME | SID | TYPE | RBS | SLOT | SEQ | LMODE | REQUEST |
1 | U1 | 143 | TM | 0 | 53224 | 0 | 5 | 0 |
2 | U1 | 143 | TX | 3 | 9 | 529 | 6 | 0 |
2 share ddl lock:
某些ddl操作在阻止一些破坏结构的ddl语句的时候也允许某些与其相似的ddl语句并行执行.比如create procedure的过程中引用了部分表对象,但这些表可以同时在另外一个存储过程创建中同时使用是不产生锁冲突. 这就是share ddl lock.
可产生share ddl lock的列表: AUDIT, NOAUDIT, COMMENT, CREATE [OR REPLACE] VIEW/ PROCEDURE/PACKAGE/PACKAGE BODY/FUNCTION/ TRIGGER, CREATE SYNONYM, and CREATE TABLE (when the CLUSTER parameter is not included).
?如何去跟踪或者捕获在这中间发生的操作呢?--如何试验?
3 Breakable parse locks
sql语句或plsql语句在共享池中持有一个他所引用的所有的对象的parse lock. 如果引用的对象被修改或删除,则该锁相关的内存共享区域会被标识为无效(invalid). 该锁的存在不会禁止ddl语句的执行,可以被破坏然后允许那些冲突的ddl语句运行,所以起名曰breakable parse lock. (当然再次运行前需要重新parse).
- DDL锁的生命周期
Exclusive 和share ddl lock生命周期是ddl的执行周期(因为ddl执行之后默认自动commit)
Breakable parse lock会随着关联的sql一起一直存在share pool直到被share pool 淘汰出去. - DDL锁和cluster(skip)
- Latch and internal locks(skip)
- Explicit(manual) data lock
- Oracle lock management services