在Oracle中有很多锁,通过v$lock_type视图可以查看Oracle中所有类型的锁,
在本篇文章中我们熟悉一下TM和TX锁的类型
SQL> select * from v$lock_type where type in (‘TM‘,‘TX‘); TYPE NAME ID1_TAG ID2_TAG IS_USER DESCRIPTION -------- --------------- ------------------ ------------------- ------- -------------------------------------------------------------------------------- TM DML object # table/partition YES Synchronizes accesses to an object TX Transaction usn<<16 | slot sequence YES Lock held by a transaction to allow other transactions to wait for it
在v$lock_type视图中可以看到对TM和TX锁的描述,TM为DML锁,TX锁是事务锁,我们知道数据库中的数据有元数据和数据,
其中元数据就是表的本身,而数据就是指表里的数据,那么TM锁保护的就是元数据,TX锁保护的就是一般意义上的数据
我们知道当truncate一张大表和truncate一张小表所花费的时间是没有差异的,原因在于Oracle在处理的时候只在删除了元数据,
而没有真正删除表里的数据,所以会很快且和表的大小无关。
通过v$lock_type可以看到
TM锁中ID1_TAG表示的是一个对象号,ID2_TAG表示的是一个对象类型,是一个表还是分区
TX锁中ID1_TAG和ID2_TAG联合起来表示的是一个事务ID(如何根据这两列算出事务ID?待续)
通过例子学习TM/TX锁
--预先创建一张表
SQL> create table test(id int,name varchar2(30)); Table created SQL> insert into test values(1,‘beijing‘); 1 row inserted SQL> commit; Commit complete
--更新一下
SQL> update test set name=‘shanghai‘ where id=1; 1 row updated
这次更新会在TEST表元数据上加上TM锁,在TEST数据上加上TX锁
SQL> select distinct sid from v$mystat; SID ---------- 153 SQL> select * from v$lock where sid=153; ADDR KADDR SID TYPE ID1 ID2 LMODE REQUEST CTIME BLOCK -------- -------- ---------- ---- ---------- ---------- ---------- ---------- ---------- ---------- 4335184C 43351864 153 TM 54663 0 3 0 264 0 4339B56C 4339B590 153 TX 458794 341 6 0 264 0
可以看到TM和TX锁,通过以上知道TM锁的ID1表示OBJECT#,
SQL> select object_name,object_type from dba_objects where object_id=54663; OBJECT_NAME OBJECT_TYPE --------------- ------------------- TEST TABLE
TX锁的ID1和ID2表示了一个事务ID,通过相应的计算能够得到事务ID,我们可以查询v$transaction
SQL> select * from v$transaction; ADDR XIDUSN XIDSLOT XIDSQN UBAFIL UBABLK UBASQN UBAREC STATUS ....... XID PRV_XID PTX_XID -------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- ----------- ---------------- ---------------- ---------------- 4339B56C 7 42 341 2 2085 481 12 ACTIVE 07002A0055010000 0000000000000000 0000000000000000
总结:
1.查询不需要锁
2.加在行上锁的一定是排他锁 exclusive (row)
3.加在表上的锁最为复杂,可分为以下几种类型 metadata (table) --也就是指v$lock表上lmode 2,3,4,5,6
4.要想锁定行首先锁定他的元数据
---开启另一会更改相同的数据观察v$lock
SQL> select distinct sid from v$mystat; SID ---------- 142 SQL> update test set name=‘guangzhou‘ where id=1;
会发现142会话被阻塞,
SQL> select * from v$lock where sid in (153,142); ADDR KADDR SID TYPE ID1 ID2 LMODE REQUEST CTIME BLOCK -------- -------- ---------- ---- ---------- ---------- ---------- ---------- ---------- ---------- 43834450 43834464 142 TX 458794 341 0 6 72 0 4335184C 43351864 153 TM 54663 0 3 0 2094 0 433518F8 43351910 142 TM 54663 0 3 0 72 0 4339B56C 4339B590 153 TX 458794 341 6 0 2094 1
发现v$lock视图153会话BLOCK为1,这就表示153会话阻塞了别的会话,可以看到142会话在请求一个REQUEST 6 的锁,
因为我们这是模拟的阻塞,我们知道153的会话阻塞了142的会话,可以看到153和142的ID1/ID2所请求或持有的资源
是一样的,从这也可判断153阻塞了142的会话
--查询session
SQL> select * from v$session where sid in (153,142); SADDR SID SERIAL# AUDSID PADDR USER# USERNAME COMMAND OWNERID TADDR LOCKWAIT STATUS SERVER SCHEMA# SCHEMANAME OSUSER PROCESS MACHINE TERMINAL PROGRAM TYPE SQL_ADDRESS SQL_HASH_VALUE SQL_ID SQL_CHILD_NUMBER PREV_SQL_ADDR PREV_HASH_VALUE PREV_SQL_ID PREV_CHILD_NUMBER PLSQL_ENTRY_OBJECT_ID PLSQL_ENTRY_SUBPROGRAM_ID PLSQL_OBJECT_ID PLSQL_SUBPROGRAM_ID MODULE MODULE_HASH ACTION ACTION_HASH CLIENT_INFO FIXED_TABLE_SEQUENCE ROW_WAIT_OBJ# ROW_WAIT_FILE# ROW_WAIT_BLOCK# ROW_WAIT_ROW# LOGON_TIME LAST_CALL_ET PDML_ENABLED FAILOVER_TYPE FAILOVER_METHOD FAILED_OVER RESOURCE_CONSUMER_GROUP PDML_STATUS PDDL_STATUS PQ_STATUS CURRENT_QUEUE_DURATION CLIENT_IDENTIFIER BLOCKING_SESSION_STATUS BLOCKING_INSTANCE BLOCKING_SESSION SEQ# EVENT# EVENT P1TEXT P1 P1RAW P2TEXT P2 P2RAW P3TEXT P3 P3RAW WAIT_CLASS_ID WAIT_CLASS# WAIT_CLASS WAIT_TIME SECONDS_IN_WAIT STATE SERVICE_NAME SQL_TRACE SQL_TRACE_WAITS SQL_TRACE_BINDS -------- ---------- ---------- ---------- -------- ---------- ------------------------------ ---------- ---------- -------- -------- -------- --------- ---------- ------------------------------ ------------------------------ ------------ ---------------------------------------------------------------- ------------------------------ ------------------------------------------------ ---------- ----------- -------------- ------------- ---------------- ------------- --------------- ------------- ----------------- --------------------- ------------------------- --------------- ------------------- ------------------------------------------------ ----------- -------------------------------- ----------- ---------------------------------------------------------------- -------------------- ------------- -------------- --------------- ------------- ----------- ------------ ------------ ------------- --------------- ----------- -------------------------------- ----------- ----------- --------- ---------------------- ---------------------------------------------------------------- ----------------------- ----------------- ---------------- ---------- ---------- ---------------------------------------------------------------- ---------------------------------------------------------------- ---------- -------- ---------------------------------------------------------------- ---------- -------- ---------------------------------------------------------------- ---------- -------- ------------- ----------- ---------------------------------------------------------------- ---------- --------------- ------------------- ---------------------------------------------------------------- --------- --------------- --------------- 44309734 142 56 4294967295 44226F64 0 SYS 6 2147483644 43395CA0 43834464 ACTIVE DEDICATED 0 SYS livan 12940:6372 WORKGROUP\LENOVO-PC LENOVO-PC plsqldev.exe USER 401CE71C 1521039957 28tf955dakfkp 0 403E63FC 356401299 9m7787camwh4m 0 PL/SQL Developer 1190136663 命令窗口 - 新建 1316471608 6083 54663 1 59602 0 2015/1/22 1 1884 NO NONE NONE NO DISABLED ENABLED ENABLED 0 VALID 1 153 51 186 enq: TX - row lock contention name|mode 1415053318 54580006 usn<<16 | slot 458794 0007002A sequence 341 00000155 4217450380 1 Application 0 1884 WAITING ZDJS DISABLED FALSE FALSE 4431717C 153 21 4294967295 442263EC 0 SYS 0 2147483644 4339B56C INACTIVE DEDICATED 0 SYS livan 12940:6372 WORKGROUP\LENOVO-PC LENOVO-PC plsqldev.exe USER 00 0 403E63FC 356401299 9m7787camwh4m 0 PL/SQL Developer 1190136663 命令窗口 - 新建 1316471608 5729 49440 3 21372 0 2015/1/22 1 3755 NO NONE NONE NO DISABLED ENABLED ENABLED 0 NO HOLDER 351 259 SQL*Net message from client driver id 1952673792 74637000 #bytes 1 00000001 0 00 2723168908 6 Idle 0 3755 WAITING ZDJS DISABLED FALSE FALSE
可以看到v$session中有一个LOCKWAIT列,改列就对应到了v$lock视图的KADDR ,其中V$LOCK中的ADDR对应到v$transaction中的ADDR找到对应的session信息,可以通过v$session中的SQL_ID找到对应的SQL
SQL> select sql_text from v$sql where sql_id=‘28tf955dakfkp‘; SQL_TEXT -------------------------------------------------------------------------------- update test set name=‘guangzhou‘ where id=1
可以看到哪个到底哪个语句被阻塞了
在v$session中可以142会话BLOCKING_SESSION_STATUS列为VALID,这也说明该会话被阻塞了,BLOCKING_SESSION列说名阻塞他的到底是哪个会话,BLOCKING_INSTANCE表示阻塞发生哪个实例
通过v$session的ROW_WAIT_OBJ#,ROW_WAIT_FILE#, ROW_WAIT_BLOCK#, ROW_WAIT_ROW#就可以求出一个ROWID,有了ROWID就知道了修改哪条数据了
SQL> select dbms_rowid.rowid_create(1,ROW_WAIT_OBJ#,ROW_WAIT_FILE#,ROW_WAIT_BLOCK#,ROW_WAIT_ROW#) 2 from v$session where sid=142; DBMS_ROWID.ROWID_CREATE(1,ROW_ ------------------------------ AAANWHAABAAAOjSAAA
根据这个rowid可以求出是哪条数据:
SQL> select * from test where rowid=‘AAANWHAABAAAOjSAAA‘; ID NAME --------------------------------------- ------------------------------ 1 beijing
lock 保护数据库对象
latch 闩 :保护的内存结构,凡是有共享的地方都有lock或latch 在同一时刻绝对是串行修改