首页 > 代码库 > 16、lock
16、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开始一个事务。
SQL> delete from t1;
1 row deleted.
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计算出事务。
SELECT trunc(t1.ID1 / power(2, 16)) XIDUSN,
bitand(t1.id1, to_number(‘ffff‘, ‘xxxx‘)) XIDSLOT,
t1.id2
FROM v$lock t1
WHERE t1.BLOCK > 0
SELECT trunc(524300 / power(2, 16)) XIDUSN,
bitand(524300 , to_number(‘ffff‘, ‘xxxx‘)) XIDSLOT,
t1.id2
FROM v$lock t1
WHERE t1.BLOCK > 0
查询结果(这个sql执行相当慢)
查询事务
select * from v$transaction;
查询结果
根据SES_ADDR查找,事务所对应的会话。
select * from v$session s where s.saddr=‘000000009358A220‘;
可以看到会话sid=9
可以用另一种方式来查看谁被谁阻塞了。
select ‘This Session‘ || ‘ ‘ || a.sid || ‘,‘ || a.serial# ||
‘ is blocked by ‘ || a.BLOCKING_SESSION
from v$session a
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上插入操作。
SQL> rollback;
Rollback complete.
SQL> select sid from v$mystat where rownum=1;
SID
----------
9
SQL> desc t1;
Name Null? Type
----------------------------------------- -------- ----------------------------
ID NUMBER
NAME VARCHAR2(20)
SQL> insert into t1 values(3,‘11‘);
1 row created.
SQL>
–查询表锁
select * from v$lock where type=‘TM‘;
看到sid为会话1,根据id1:92686 知道是表t1(刚才查过了),根据LMODE是3可以知道是sx锁。
2、在会话2上执行for update
SQL> select sid from v$mystat where rownum=1;
SID
----------
814
SQL> select * from t1;
ID NAME
---------- --------------------
2 zyr
SQL> select * from t1 where ID=2 for update;
ID NAME
---------- --------------------
2 zyr
SQL>
我们知道访问一个表使用for update会在一个表上加ss锁。
我们查看一下。
–查询表锁
select * from v$lock where type=‘TM‘;
可以看到LMODE是3查看LMODE表可以看到是SX锁,和预想的不太一样,实际上SS和SX是一样的,都是在行上加锁。
3、在会话3上执行删除表。可以看到资源正忙,因为这个表正在被其他会话修改。
SQL> drop table t1;
drop table t1
*
ERROR at line 1:
ORA-00054: resource busy and acquire with NOWAIT specified or timeout expired
SQL>
注意11g新特性。可以设置超时时间。
查询参数
SQL> show parameter time
NAME TYPE VALUE
awr_snapshot_time_offset integer 0
control_file_record_keep_time integer 7
cursor_space_for_time boolean FALSE
ddl_lock_timeout integer 0
设置会话超时时间为100秒
SQL> alter session set ddl_lock_timeout=100;
Session altered.
SQL>
再次执行删除表t1的操作。
SQL> drop table t1;
–查询表锁
select * from v$lock where type=‘TM‘;
可以看到sid 会话id为18的会话,LMODE为6,查看锁类型为x。
使用会话4,手动的加rx锁。
SQL> lock table t1 in row exclusive mode;
Table(s) Locked.
SQL>
使用会话5手动申请x锁。
SQL> lock table t1 in exclusive mode;
会话4转换锁
SQL> lock table t1 in row exclusive mode;
Table(s) Locked.
SQL> lock table t1 in exclusive mode;
Table(s) Locked.
SQL>
释放会话1、2、3的锁,可以看到会话4首先占用了x锁。
系统夯住怎么办
1、会话占用同一个资源,无法获取到资源。
2、少数会话将一个会话夯住了,
解决夯住的办法是
hang
1、都在等待一个资源
2、被另一个会话锁住。
解决办法。
1、sqlplus登陆,查询
2、hanganalyze、sysstate dump
模拟一个系统夯住的情况。
四个会话都执行删除t1表。
delete from t1;
1,查到进程号,直接用操作系统杀死进程。
查看谁被谁阻塞了。
select ‘This Session‘ || ‘ ‘ || a.sid || ‘,‘ || a.serial# ||
‘ is blocked by ‘ || a.BLOCKING_SESSION
from v$session a
where a.BLOCKING_SESSION is not null;
结果是
查询会话sid 为 9的会话进程
select spid from v$process a,v$session b where a.addr=b.paddr and b.sid=9;
结构是
杀掉进程号为 2894的进程
[root@oracle ~]# ps -ef |grep 2894
oracle 2894 2826 0 14:26 ? 00:00:02 oracleoracl (DESCRIPTION=(LOCAL=YES)(ADDRESS=(PROTOCOL=beq)))
root 5114 5057 0 19:32 pts/4 00:00:00 grep 2894
[root@oracle ~]# kill -9 2894
[root@oracle ~]#
2、使用oradebug
1、SQL> oradebug help
HELP [command] Describe one or all commands
SETMYPID Debug current process
SETOSPID <ospid> Set OS pid of process to debug
SETORAPID <orapid> [‘force‘] Set Oracle pid of process to debug
SETORAPNAME <orapname> Set Oracle process name to debug
SHORT_STACK Get abridged OS stack
CURRENT_SQL Get current SQL
DUMP <dump_name> <lvl> [addr] Invoke named dump
PDUMP [interval=<interval>] Invoke named dump periodically
[ndumps=<count>] <dump_name> <lvl> [addr]
DUMPSGA [bytes] Dump fixed SGA
DUMPLIST Print a list of available dumps
EVENT <text> Set trace event in process
SESSION_EVENT <text> Set trace event in session
DUMPVAR <p|s|uga> <name> [level] Print/dump a fixed PGA/SGA/UGA variable
DUMPTYPE <address> <type> <count> Print/dump an address with type info
SETVAR <p|s|uga> <name> <value> Modify a fixed PGA/SGA/UGA variable
PEEK <addr> <len> [level] Print/Dump memory
POKE <addr> <len> <value> Modify memory
WAKEUP <orapid> Wake up Oracle process
SUSPEND Suspend execution
RESUME Resume execution
FLUSH Flush pending writes to trace file
CLOSE_TRACE Close trace file
TRACEFILE_NAME Get name of trace file
SETTRACEFILEID <identifier name> Set tracefile identifier
LKDEBUG Invoke global enqueue service debugger
NSDBX Invoke CGS name-service debugger
-G <Inst-List | def | all> Parallel oradebug command prefix
-R <Inst-List | def | all> Parallel oradebug prefix (return output
SETINST <instance# .. | all> Set instance list in double quotes
SGATOFILE <SGA dump dir> Dump SGA to file; dirname in double quotes
DMPCOWSGA <SGA dump dir> Dump & map SGA as COW; dirname in double quotes
MAPCOWSGA <SGA dump dir> Map SGA as COW; dirname in double quotes
HANGANALYZE [level] [syslevel] Analyze system hang
FFBEGIN Flash Freeze the Instance
FFDEREGISTER FF deregister instance from cluster
FFTERMINST Call exit and terminate instance
FFRESUMEINST Resume the flash frozen instance
FFSTATUS Flash freeze status of instance
SKDSTTPCS <ifname> <ofname> Helps translate PCs to names
WATCH <address> <len> <self|exist|all|target> Watch a region of memory
DELETE <local|global|target> watchpoint <id> Delete a watchpoint
SHOW <local|global|target> watchpoints Show watchpoints
DIRECT_ACCESS <set/enable/disable command | select query> Fixed table access
IPC Dump ipc information
UNLIMIT Unlimit the size of the trace file
CALL [-t count] <func> [arg1]...[argn] Invoke function with arguments
CORE Dump core without crashing process
PROCSTAT Dump process statistics
SQL>
2、oradebug setmypid用当前会话登陆做数据分析。
SQL> oradebug setmypid
Statement processed.
SQL>
3、oradebug unlimit 不限制文件的大小。
SQL> oradebug unlimit
Statement processed.
SQL>
查看dumplist
4、用级别3 oradebug dump hanganalyze 3
SQL> oradebug dump hanganalyze 3
Statement processed.
SQL>
5、文件地址
SQL> oradebug tracefile_name
/u01/app/oracle/diag/rdbms/oracl/oracl/trace/oracl_ora_3039.trc
SQL>
6、退出查看文件
3、sqlplus -prelim / as sysdba
我们知道当一个数据库hang住时,最头痛的问题是无法登陆数据,也就无法进行故障的处理,因此很多人只能通过重启
操作系统来讲解决问题,其实从Oracle 10g开始,Oracle提供了prelim的登陆方式,如下:
sqlplus -prelim / as sysdba
oradebug setospid <process ID>
oradebug unlimit
oradebug dump systemstate 10
其他方法同上一个。
4、gdb
[root@oracle ~]# ps -ef |grep LOCAL
oracle 2989 2988 0 14:27 ? 00:00:01 oracleoracl (DESCRIPTION=(LOCAL=YES)(ADDRESS=(PROTOCOL=beq)))
oracle 4196 4195 0 17:19 ? 00:00:00 oracleoracl (DESCRIPTION=(LOCAL=YES)(ADDRESS=(PROTOCOL=beq)))
root 5455 5057 0 20:19 pts/4 00:00:00 grep LOCAL
[root@oracle usr]# cd /usr/bin
[root@oracle bin]# ls gdb
gdb
[root@oracle bin]#
[root@oracle bin]# chmod +s gdb
[root@oracle bin]# ll gdb
-rwsr-sr-x 1 root root 4493600 Apr 24 2013 gdb
[root@oracle bin]#
[oracle@oracle ~]$ gdb $ORACLE_HOME/bin/oracle 2989 ---用2989会话
gdb) print ksudss(10) ---开始
$1 = 0
(gdb) detach --结束
Detaching from program: /u01/app/oracle/product/11.2.0/db_1/bin/oracle, process 2989
(gdb)
用另一个窗口。查看文件。
[oracle@oracle ~]$ cd $LOG
[oracle@oracle trace]$ ll -t|more
total 2072
-rw-r----- 1 oracle oinstall 9535 Feb 15 20:24 oracl_mmon_2860.trc
-rw-r----- 1 oracle oinstall 943 Feb 15 20:24 oracl_mmon_2860.trm
-rw-r----- 1 oracle oinstall 890164 Feb 15 20:24 oracl_ora_2989.trc
-rw-r----- 1 oracle oinstall 95905 Feb 15 20:24 oracl_ora_2989.trm
-rw-r----- 1 oracle oinstall 319205 Feb 15 20:24 alert_oracl.log
-rw-r----- 1 oracle oinstall 20159 Feb 15 19:51 oracl_ora_3039.trc
-rw-r----- 1 oracle oinstall 2304 Feb 15 19:51 oracl_ora_3039.trm
-rw-r----- 1 oracle oinstall 952 Feb 15 19:00 oracl_j001_4837.trc
-rw-r----- 1 oracle oinstall 69 Feb 15 19:00 oracl_j001_4837.trm
[oracle@oracle trace]$ vi oracl_ora_2989.trc
[oracle@oracle trace]$ 发现很难看懂用工具格式化一下。
将文件复制到
[oracle@oracle trace]$ pwd
/u01/app/oracle/diag/rdbms/oracl/oracl/trace
[oracle@oracle trace]$ ls ass109.awk
ass109.awk
[oracle@oracle trace]$
[oracle@oracle trace]$ awk -f ass109.awk oracl_ora_2989.trc--进行格式化
40: 0: waiting for ‘Streams AQ: qmn slave idle wait‘
41: 9: waited for ‘Streams AQ: waiting for time management or cleanup tasks‘
42: 0: waiting for ‘SQL*Net message from client‘
44: 0: waiting for ‘rdbms ipc message‘
45: 0: waiting for ‘rdbms ipc message‘
47: 0: waiting for ‘enq: TX - row lock contention‘[Enqueue TX-00080011-000028F5]
Blockers
~~~~~~~~
Above is a list of all the processes. If they are waiting for a resource
then it will be given in square brackets. Below is a summary of the
waited upon resources, together with the holder of that resource.
Notes:
~~~~~
o A process id of ‘???‘ implies that the holder was not found in the
systemstate.
Resource Holder State
Enqueue TX-00080011-000028F5 42: 0: waiting for ‘SQL*Net message from client‘---42号持有这个事务
Object Names
~~~~~~~~~~~~
Enqueue TX-00080011-000028F5
33961 Lines Processed.
[oracle@oracle trace]$
[oracle@oracle trace]$ vi oracl_ora_2989.trc
PROCESS 42:
----------------------------------------
SO: 0x94711480, type: 2, owner: (nil), flag: INIT/-/-/0x00 if: 0x3 c: 0x3
proc=0x94711480, name=process, file=ksu.h LINE:12721, pg=0
(process) Oracle pid:42, ser:2, calls cur/top: (nil)/0x70dde2c8
flags : (0x0) -
flags2: (0x1000), flags3: (0x10)
intr error: 0, call error: 0, sess error: 0, txn error 0
intr queue: empty
ksudlp FALSE at location: 0
(post info) last post received: 0 0 9
last post received-location: ksq.h LINE:2015 ID:ksqrcl
last process to post me: 0x94712538 13 0
last post sent: 0 0 9
last post sent-location: ksq.h LINE:2015 ID:ksqrcl
last process posted by me: 0x94716818 32 0
(latch info) wait_event=0 bits=0x0
Process Group: DEFAULT, pseudo proc: 0x943696a8
O/S info: user: oracle, term: UNKNOWN, ospid: 2989
OSD pid info: Unix process pid: 2989, image: oracle@oracle (TNS V1-V3)
/pid:42---查找pid为42的操作系统的pid
查看操作系统是否有这个2989的进程呢。
[oracle@oracle trace]$ ps -ef |grep 2989
oracle 2989 2988 0 14:27 ? 00:00:01 oracleoracl (DESCRIPTION=(LOCAL=YES)(ADDRESS=(PROTOCOL=beq)))
root 5788 5479 0 20:46 pts/4 00:00:01 gdb /u01/app/oracle/product/11.2.0/db_1/bin/oracle 2989
oracle 5873 5564 0 20:59 pts/5 00:00:00 grep 2989
[oracle@oracle trace]$
select spid from v$process a,v$session b where a.addr=b.paddr and b.sid=42;
16、lock