首页 > 代码库 > 16、lock

16、lock

lock
锁的相关概念
latch
锁的粒度
表锁tm
模拟一个被锁住的情况,分析阻塞源头。
模拟环境
分析锁的源头的过程
oracle数据库的锁
锁的兼容性
系统夯住怎么办
1,查到进程号,直接用操作系统杀死进程。
2、使用oradebug
3、sqlplus -prelim / as sysdba
4、gdb

lock

锁的相关概念

sga区叫共享全局区(系统共享区)很多个进程都可以访问。
使用锁来解决共享资源的并发问题。锁一般是个内存结构。

latch

提到锁来回顾一下latch锁。latch是个内存结构。
要修改数据就要持有latch。
latch和mutex
1、如果无法持有latch,不退出cpu,随机的等待,再次尝试持有(在这期间可能其他进程抢先持有,没有排队),多次无法持有将释放cpu。
详细内容请见前面解析8。

锁的粒度

1、前一个进程latch释放
2、本进程ping住buffer,修改数据。修改完成释放ping。
3、没有提交。见前面的。undo。

oracle数据库中,dml加的是行锁而不是块锁,ping住是修改的瞬间。数据不提交,行锁一直不释放。粒度很小。产生冲突的可能性很小。

表锁tm

oracle数据库也可能加表锁。
1、修改一个行,就加了一个行锁tm:rx锁。
2、要删除drop 一个表。就在表上加 tm:x锁。
sp1修改了一个表中的行在一个表上加 tm :rx锁,未提交。sp2 要drop 掉了这个表,要在tm:x ,sp2就加不上锁。

表锁的关系。
tm:rx 和tm:x冲突。
tm:rx和tm:rx是不冲突。
tm:x和tm:x冲突。
for update表上是tm:rs 行上是rx锁。
dml不阻塞select。

事务锁有事务等待引起的排队,

锁的排队机制。

持有者,转换者队列。


模拟一个被锁住的情况,分析阻塞源头。

oracle锁
tx
tm
查看
select * from v$lock_type a where a.TYPE in (‘TM‘,‘TX‘);
有两个参数。

技术分享

模拟环境

1、客户端1开始一个事务。

  1. SQL> delete from t1;
  2. 1 row deleted.
  3. SQL>

2、会话2访问t1表
SQL> delete from t1;
3、会话3删除t1
SQL> delete from t1;

分析锁的源头的过程

从v$lock视图中查询类型为TM和TX的锁。
select * from v$lock l where l.type in (‘TM‘,‘TX‘);
结果

技术分享

select * from v$lock l where l.type in (‘TM‘,‘TX‘) order by sid; —对结果排序。

技术分享

sid会话号。LMODE持有类型。CTIME持有时间。

查询是在哪个对象上持有的。
select * from dba_objects o where o.object_id=92686;

技术分享

持有模式LMODE类型参考下图。

技术分享

LMODE为6表示以x方式持有表。(被这个事务所阻塞。)
事务xid有三部分组成,段号,事务表槽位号,第几次被覆盖。

段号,事务表槽位号 第几次被覆盖
ID1 ID2

说明sid为9、18、814的会话,都被 ID1:524300 和 ID2:10472所决定的事务所阻塞了。

根据ID1计算出事务。

  1. SELECT trunc(t1.ID1 / power(2, 16)) XIDUSN,
  2. bitand(t1.id1, to_number(‘ffff‘, ‘xxxx‘)) XIDSLOT,
  3. t1.id2
  4. FROM v$lock t1
  5. WHERE t1.BLOCK > 0
  1. SELECT trunc(524300 / power(2, 16)) XIDUSN,
  2. bitand(524300 , to_number(‘ffff‘, ‘xxxx‘)) XIDSLOT,
  3. t1.id2
  4. FROM v$lock t1
  5. WHERE t1.BLOCK > 0

查询结果(这个sql执行相当慢)

技术分享

查询事务
select * from v$transaction;
查询结果

技术分享

技术分享

根据SES_ADDR查找,事务所对应的会话。

select * from v$session s where s.saddr=‘000000009358A220‘;
可以看到会话sid=9

技术分享

可以用另一种方式来查看谁被谁阻塞了。

  1. select ‘This Session‘ || ‘ ‘ || a.sid || ‘,‘ || a.serial# ||
  2. ‘ is blocked by ‘ || a.BLOCKING_SESSION
  3. from v$session a
  4. where a.BLOCKING_SESSION is not null;

结果
技术分享


oracle数据库的锁

技术分享

oracle数据库的锁
1、TX
2、TM

修改一个数据行,在数据行上加上了一个行锁
另外一个会话想修改相同的行的时候,被锁住,表现为

1号会话所对应的事务锁住了2号会话所对应的事务
TX锁

我们在一个表的一个数据行上加了一个行锁,那么Oracle在这个表上加上一个RX锁(TM)
修改行,加行锁,会在表上加表锁。
rx和rx是相互兼容的。


锁的兼容性


1、TX(作用在行上)
只有排他锁,是互斥的,条件是修改相同的数据行。
2、TM(作用在表上)

表上操作类型 表上锁类型
insert 、delete、update SX锁
for update SS(RS)锁
ddl X锁
create index s锁

lock table手动加锁。

技术分享

首先在三个会话上执行回滚操作。
1、在会话1上插入操作。

  1. SQL> rollback;
  2. Rollback complete.
  3. SQL> select sid from v$mystat where rownum=1;
  4. SID
  5. ----------
  6. 9
  7. SQL> desc t1;
  8. Name Null? Type
  9. ----------------------------------------- -------- ----------------------------
  10. ID NUMBER
  11. NAME VARCHAR2(20)
  12. SQL> insert into t1 values(3,‘11‘);
  13. 1 row created.
  14. SQL>

–查询表锁
select * from v$lock where type=‘TM‘;

技术分享

看到sid为会话1,根据id1:92686 知道是表t1(刚才查过了),根据LMODE是3可以知道是sx锁。

2、在会话2上执行for update

  1. SQL> select sid from v$mystat where rownum=1;
  2. SID
  3. ----------
  4. 814
  5. SQL> select * from t1;
  6. ID NAME
  7. ---------- --------------------
  8. 2 zyr
  9. SQL> select * from t1 where ID=2 for update;
  10. ID NAME
  11. ---------- --------------------
  12. 2 zyr
  13. SQL>

我们知道访问一个表使用for update会在一个表上加ss锁。
我们查看一下。

–查询表锁
select * from v$lock where type=‘TM‘;

技术分享

可以看到LMODE是3查看LMODE表可以看到是SX锁,和预想的不太一样,实际上SS和SX是一样的,都是在行上加锁。

3、在会话3上执行删除表。可以看到资源正忙,因为这个表正在被其他会话修改。

  1. SQL> drop table t1;
  2. drop table t1
  3. *
  4. ERROR at line 1:
  5. ORA-00054: resource busy and acquire with NOWAIT specified or timeout expired
  6. SQL>

注意11g新特性。可以设置超时时间。

  1. 查询参数
  2. SQL> show parameter time
  3. NAME TYPE VALUE
  4. awr_snapshot_time_offset integer 0
  5. control_file_record_keep_time integer 7
  6. cursor_space_for_time boolean FALSE
  7. ddl_lock_timeout integer 0
  8. 设置会话超时时间为100
  9. SQL> alter session set ddl_lock_timeout=100;
  10. Session altered.
  11. SQL>

再次执行删除表t1的操作。

  1. SQL> drop table t1;

–查询表锁
select * from v$lock where type=‘TM‘;

技术分享

可以看到sid 会话id为18的会话,LMODE为6,查看锁类型为x。

技术分享

使用会话4,手动的加rx锁。

  1. SQL> lock table t1 in row exclusive mode;
  2. Table(s) Locked.
  3. SQL>

使用会话5手动申请x锁。

  1. SQL> lock table t1 in exclusive mode;

会话4转换锁

  1. SQL> lock table t1 in row exclusive mode;
  2. Table(s) Locked.
  3. SQL> lock table t1 in exclusive mode;
  4. Table(s) Locked.
  5. SQL>

释放会话1、2、3的锁,可以看到会话4首先占用了x锁。


系统夯住怎么办

1、会话占用同一个资源,无法获取到资源。
2、少数会话将一个会话夯住了,

解决夯住的办法是

hang
1、都在等待一个资源
2、被另一个会话锁住。
解决办法。
1、sqlplus登陆,查询
2、hanganalyze、sysstate dump

模拟一个系统夯住的情况。
四个会话都执行删除t1表。

  1. delete from t1;

1,查到进程号,直接用操作系统杀死进程。

查看谁被谁阻塞了。

  1. select ‘This Session‘ || ‘ ‘ || a.sid || ‘,‘ || a.serial# ||
  2. ‘ is blocked by ‘ || a.BLOCKING_SESSION
  3. from v$session a
  4. where a.BLOCKING_SESSION is not null;

结果是
技术分享
查询会话sid 为 9的会话进程

  1. select spid from v$process a,v$session b where a.addr=b.paddr and b.sid=9;

结构是
技术分享
杀掉进程号为 2894的进程

  1. [root@oracle ~]# ps -ef |grep 2894
  2. oracle 2894 2826 0 14:26 ? 00:00:02 oracleoracl (DESCRIPTION=(LOCAL=YES)(ADDRESS=(PROTOCOL=beq)))
  3. root 5114 5057 0 19:32 pts/4 00:00:00 grep 2894
  4. [root@oracle ~]# kill -9 2894
  5. [root@oracle ~]#

2、使用oradebug

1、SQL> oradebug help

  1. HELP [command] Describe one or all commands
  2. SETMYPID Debug current process
  3. SETOSPID <ospid> Set OS pid of process to debug
  4. SETORAPID <orapid> [‘force‘] Set Oracle pid of process to debug
  5. SETORAPNAME <orapname> Set Oracle process name to debug
  6. SHORT_STACK Get abridged OS stack
  7. CURRENT_SQL Get current SQL
  8. DUMP <dump_name> <lvl> [addr] Invoke named dump
  9. PDUMP [interval=<interval>] Invoke named dump periodically
  10. [ndumps=<count>] <dump_name> <lvl> [addr]
  11. DUMPSGA [bytes] Dump fixed SGA
  12. DUMPLIST Print a list of available dumps
  13. EVENT <text> Set trace event in process
  14. SESSION_EVENT <text> Set trace event in session
  15. DUMPVAR <p|s|uga> <name> [level] Print/dump a fixed PGA/SGA/UGA variable
  16. DUMPTYPE <address> <type> <count> Print/dump an address with type info
  17. SETVAR <p|s|uga> <name> <value> Modify a fixed PGA/SGA/UGA variable
  18. PEEK <addr> <len> [level] Print/Dump memory
  19. POKE <addr> <len> <value> Modify memory
  20. WAKEUP <orapid> Wake up Oracle process
  21. SUSPEND Suspend execution
  22. RESUME Resume execution
  23. FLUSH Flush pending writes to trace file
  24. CLOSE_TRACE Close trace file
  25. TRACEFILE_NAME Get name of trace file
  26. SETTRACEFILEID <identifier name> Set tracefile identifier
  27. LKDEBUG Invoke global enqueue service debugger
  28. NSDBX Invoke CGS name-service debugger
  29. -G <Inst-List | def | all> Parallel oradebug command prefix
  30. -R <Inst-List | def | all> Parallel oradebug prefix (return output
  31. SETINST <instance# .. | all> Set instance list in double quotes
  32. SGATOFILE <SGA dump dir> Dump SGA to file; dirname in double quotes
  33. DMPCOWSGA <SGA dump dir> Dump & map SGA as COW; dirname in double quotes
  34. MAPCOWSGA <SGA dump dir> Map SGA as COW; dirname in double quotes
  35. HANGANALYZE [level] [syslevel] Analyze system hang
  36. FFBEGIN Flash Freeze the Instance
  37. FFDEREGISTER FF deregister instance from cluster
  38. FFTERMINST Call exit and terminate instance
  39. FFRESUMEINST Resume the flash frozen instance
  40. FFSTATUS Flash freeze status of instance
  41. SKDSTTPCS <ifname> <ofname> Helps translate PCs to names
  42. WATCH <address> <len> <self|exist|all|target> Watch a region of memory
  43. DELETE <local|global|target> watchpoint <id> Delete a watchpoint
  44. SHOW <local|global|target> watchpoints Show watchpoints
  45. DIRECT_ACCESS <set/enable/disable command | select query> Fixed table access
  46. IPC Dump ipc information
  47. UNLIMIT Unlimit the size of the trace file
  48. CALL [-t count] <func> [arg1]...[argn] Invoke function with arguments
  49. CORE Dump core without crashing process
  50. PROCSTAT Dump process statistics
  51. SQL>

2、oradebug setmypid用当前会话登陆做数据分析。

  1. SQL> oradebug setmypid
  2. Statement processed.
  3. SQL>

3、oradebug unlimit 不限制文件的大小。

  1. SQL> oradebug unlimit
  2. Statement processed.
  3. SQL>

查看dumplist

4、用级别3 oradebug dump hanganalyze 3

  1. SQL> oradebug dump hanganalyze 3
  2. Statement processed.
  3. SQL>

5、文件地址

  1. SQL> oradebug tracefile_name
  2. /u01/app/oracle/diag/rdbms/oracl/oracl/trace/oracl_ora_3039.trc
  3. SQL>

6、退出查看文件

3、sqlplus -prelim / as sysdba

我们知道当一个数据库hang住时,最头痛的问题是无法登陆数据,也就无法进行故障的处理,因此很多人只能通过重启
操作系统来讲解决问题,其实从Oracle 10g开始,Oracle提供了prelim的登陆方式,如下:

  1. sqlplus -prelim / as sysdba
  2. oradebug setospid <process ID>
  3. oradebug unlimit
  4. oradebug dump systemstate 10

其他方法同上一个。

4、gdb

  1. [root@oracle ~]# ps -ef |grep LOCAL
  2. oracle 2989 2988 0 14:27 ? 00:00:01 oracleoracl (DESCRIPTION=(LOCAL=YES)(ADDRESS=(PROTOCOL=beq)))
  3. oracle 4196 4195 0 17:19 ? 00:00:00 oracleoracl (DESCRIPTION=(LOCAL=YES)(ADDRESS=(PROTOCOL=beq)))
  4. root 5455 5057 0 20:19 pts/4 00:00:00 grep LOCAL
  1. [root@oracle usr]# cd /usr/bin
  2. [root@oracle bin]# ls gdb
  3. gdb
  4. [root@oracle bin]#
  5. [root@oracle bin]# chmod +s gdb
  6. [root@oracle bin]# ll gdb
  7. -rwsr-sr-x 1 root root 4493600 Apr 24 2013 gdb
  8. [root@oracle bin]#
  9. [oracle@oracle ~]$ gdb $ORACLE_HOME/bin/oracle 2989 ---用2989会话
  10. gdb) print ksudss(10) ---开始
  11. $1 = 0
  12. (gdb) detach --结束
  13. Detaching from program: /u01/app/oracle/product/11.2.0/db_1/bin/oracle, process 2989
  14. (gdb)

用另一个窗口。查看文件。

  1. [oracle@oracle ~]$ cd $LOG
  2. [oracle@oracle trace]$ ll -t|more
  3. total 2072
  4. -rw-r----- 1 oracle oinstall 9535 Feb 15 20:24 oracl_mmon_2860.trc
  5. -rw-r----- 1 oracle oinstall 943 Feb 15 20:24 oracl_mmon_2860.trm
  6. -rw-r----- 1 oracle oinstall 890164 Feb 15 20:24 oracl_ora_2989.trc
  7. -rw-r----- 1 oracle oinstall 95905 Feb 15 20:24 oracl_ora_2989.trm
  8. -rw-r----- 1 oracle oinstall 319205 Feb 15 20:24 alert_oracl.log
  9. -rw-r----- 1 oracle oinstall 20159 Feb 15 19:51 oracl_ora_3039.trc
  10. -rw-r----- 1 oracle oinstall 2304 Feb 15 19:51 oracl_ora_3039.trm
  11. -rw-r----- 1 oracle oinstall 952 Feb 15 19:00 oracl_j001_4837.trc
  12. -rw-r----- 1 oracle oinstall 69 Feb 15 19:00 oracl_j001_4837.trm
  13. [oracle@oracle trace]$ vi oracl_ora_2989.trc
  14. [oracle@oracle trace]$ 发现很难看懂用工具格式化一下。
  15. 将文件复制到
  16. [oracle@oracle trace]$ pwd
  17. /u01/app/oracle/diag/rdbms/oracl/oracl/trace
  18. [oracle@oracle trace]$ ls ass109.awk
  19. ass109.awk
  20. [oracle@oracle trace]$
  21. [oracle@oracle trace]$ awk -f ass109.awk oracl_ora_2989.trc--进行格式化

技术分享

  1. 40: 0: waiting for ‘Streams AQ: qmn slave idle wait‘
  2. 41: 9: waited for ‘Streams AQ: waiting for time management or cleanup tasks‘
  3. 42: 0: waiting for ‘SQL*Net message from client‘
  4. 44: 0: waiting for ‘rdbms ipc message‘
  5. 45: 0: waiting for ‘rdbms ipc message‘
  6. 47: 0: waiting for ‘enq: TX - row lock contention‘[Enqueue TX-00080011-000028F5]
  7. Blockers
  8. ~~~~~~~~
  9. Above is a list of all the processes. If they are waiting for a resource
  10. then it will be given in square brackets. Below is a summary of the
  11. waited upon resources, together with the holder of that resource.
  12. Notes:
  13. ~~~~~
  14. o A process id of ‘???‘ implies that the holder was not found in the
  15. systemstate.
  16. Resource Holder State
  17. Enqueue TX-00080011-000028F5 42: 0: waiting for ‘SQL*Net message from client‘---42号持有这个事务
  18. Object Names
  19. ~~~~~~~~~~~~
  20. Enqueue TX-00080011-000028F5
  21. 33961 Lines Processed.
  22. [oracle@oracle trace]$
  1. [oracle@oracle trace]$ vi oracl_ora_2989.trc
  2. PROCESS 42:
  3. ----------------------------------------
  4. SO: 0x94711480, type: 2, owner: (nil), flag: INIT/-/-/0x00 if: 0x3 c: 0x3
  5. proc=0x94711480, name=process, file=ksu.h LINE:12721, pg=0
  6. (process) Oracle pid:42, ser:2, calls cur/top: (nil)/0x70dde2c8
  7. flags : (0x0) -
  8. flags2: (0x1000), flags3: (0x10)
  9. intr error: 0, call error: 0, sess error: 0, txn error 0
  10. intr queue: empty
  11. ksudlp FALSE at location: 0
  12. (post info) last post received: 0 0 9
  13. last post received-location: ksq.h LINE:2015 ID:ksqrcl
  14. last process to post me: 0x94712538 13 0
  15. last post sent: 0 0 9
  16. last post sent-location: ksq.h LINE:2015 ID:ksqrcl
  17. last process posted by me: 0x94716818 32 0
  18. (latch info) wait_event=0 bits=0x0
  19. Process Group: DEFAULT, pseudo proc: 0x943696a8
  20. O/S info: user: oracle, term: UNKNOWN, ospid: 2989
  21. OSD pid info: Unix process pid: 2989, image: oracle@oracle (TNS V1-V3)
  22. /pid:42---查找pid42的操作系统的pid

查看操作系统是否有这个2989的进程呢。

  1. [oracle@oracle trace]$ ps -ef |grep 2989
  2. oracle 2989 2988 0 14:27 ? 00:00:01 oracleoracl (DESCRIPTION=(LOCAL=YES)(ADDRESS=(PROTOCOL=beq)))
  3. root 5788 5479 0 20:46 pts/4 00:00:01 gdb /u01/app/oracle/product/11.2.0/db_1/bin/oracle 2989
  4. oracle 5873 5564 0 20:59 pts/5 00:00:00 grep 2989
  5. [oracle@oracle trace]$
  1. select spid from v$process a,v$session b where a.addr=b.paddr and b.sid=42;


null


16、lock