Oracle中锁的产生和解锁.docx
《Oracle中锁的产生和解锁.docx》由会员分享,可在线阅读,更多相关《Oracle中锁的产生和解锁.docx(23页珍藏版)》请在冰点文库上搜索。
Oracle中锁的产生和解锁
Oracle中锁的产品和解锁
文档修改记录
版本号
日期
说明
编写者
审核者
V1.0
20110822
初稿
周伟明
1Oracle锁的介绍
在多进程或者多线程业务系统中,多个Oracle用户可以同时登录到一个Oracle数据库,对数据库中的数据进行操作难免会出现同时访问同一数据(表或者表中某一条记录)的情况,如果不对这种情况进行规范操作,数据的一致性和完整性就得不到保证,从而会出现意想不到的结果,所以必须有一种机制对并发访问进行控制和调度,避免造成数据更新不正确。
Oracle锁就是这样一种机制,它是控制并发操作最常用的方法。
Oracle使用锁来防止进程相互之间发生的破坏性影响,当一个进程企图阻止另外一个进程对某条数据操作时,该进程就对这个数据进行锁,别的进程对这个数据操作之前,必须获得这个数据的解锁。
Oracle锁功能是OracleDBMS自动完成的,不需要用户干预,但Oracle也提供了加锁的命令,供用户使用。
1.1Oracle锁机制
Oracle自动使用不同锁类型来控制数据的并发操作,以防止用户之间的破坏性干扰。
Oracle为一个事务自动锁一个资源,以防止其他事务对同一个资源的排他锁。
当某种条件出现或者事务不再需要该资源时,锁自动解除。
Oracle自动获取不同类型的锁取决于锁的资源及其所执行的操作。
其中包括数据锁(DML)、字典锁(DDL)、内部锁、人工锁定、分布锁和并行缓冲管理锁。
1.1.1数据锁(DML)模式
数据锁保证表中数据在多个用户并发操作数据时保证数据的完整性,并防止相冲突的DML和DDL操作的破坏性干扰。
DML操作可在两个级别获取数据锁:
行级锁(TX)和表级锁(TM)。
表级锁有以下几种方式
●空
Null,即无锁。
●行共享表锁(RS)
行共享表锁(有时也叫SS),表明事务保持已锁表行的表锁,并试图修改数据。
这种锁是在执行以下命令的时自动获取:
Select…From表名…forupdatefor…;
LockTable表名inRowShareMode;
当一个事务在一个表持有行共享锁的时候,允许其他事务并行查询、插入、修改或者删除及再进行行锁,但禁止其他事务以排他方式进行操作该表。
LockTable表名inExclusiveMode;
●行排他表锁(RX)
行排他表锁(有时也叫SX)表示该事务对该资源有独占权利,通常是在修改记录时发生这种锁。
该锁在执行以下命令的时候自动获取:
InsertInto表名…;
Update表名…;
DeleteFrom表名…;
LockTable表名InRowExclusiveMode;
当一个事务在一个表上持有行排他锁时,允许其他事务并行查询、插入、删除、修改或者锁同一个表的其他行,但禁止其他事务使用下列命令进行并发锁:
LockTable表名InShareMode;
LockTable表名InShareRowExclusiveMode;
LockTable表名InExclusiveMode;
●共享表锁(S)
拥有共享表锁的事务允许其他事务查询该表,或用Select…ForUpdate锁住指定的行,和取得他们自己的ShareTable锁(LockTableInShareMode),但其他事务不能修改该表。
实现共享表锁使用如下命令:
LockTable表名InShareTable;
但是禁止其他事务使用下列命令进行并发锁:
LockTable表名InShareExclusiveMode;
LockTable表名InRowExclusiveMode;
LockTable表名InExclusiveMode;
●共享行排他表锁(SRX)
这种锁比共享锁具有更多限制,它只允许其他事务做查询,或用Select…ForUpdate锁指定的行,但不允许修改表。
实现共享行排他表锁使用如下命令:
LockTable表名InShareRowExclusiveMode;
一旦表使用了这种锁,下列锁均不可使用:
LockTable表名InShareMode;
LockTable表名InShareRowExclusiveMode;
LockTable表名InExclusiveMode;
●排他表锁(X)
排他表锁是最严格的方式,一个表只允许一个排他表锁存在,Exclusive允许持有锁的事务对该表读取操作,其他事务只可以查询操作,插入、删除、修改等操作均不允许,也不允许取得任何形式的锁。
实现排他表锁使用如下命令:
LockTable表名InExclusiveMode;
1.1.2字典锁(DDL)模式
DDL锁保证模式对象(如表)的定义,DDL操作将影响对象;一个DDL命令隐式地提交一个事务,当DDL事务需要时,由Oracle自动获取字典锁,用户不能显式地请求DDL锁。
1.1.3内部锁模式
内部用户保证Oracle内部结构,而这些内部结构是不能访问的,所以用户无需对他们深入了解。
1.1.4死锁
死锁是多用户系统可能发生的一种现象,通常这种情况比较少,但是一般出现就比较致命。
当两个或者多个进程相互等待对方释放资源而没有一个进程可以继续的时候,就造成了死锁,具体如下:
●实例1:
事务T1:
Updatefundreala
Seta.current_balane=a.current_balane+v_current_balane
Wherea.fund_account=‘100000’;
Updatefundserialcountera
Seta.serial_counter_value=a.serial_counter_value+1;
Wherea.serial_counter_no=1;
事务T2:
Updatefundserialcountera
Seta.serial_counter_value=a.serial_counter_value+1;
Wherea.serial_counter_no=1;
Updatefundreala
Seta.current_balane=a.current_balane+v_current_balane
Wherea.fund_account=‘100000’;
当T1事务在修改fundreal表记录的时候,T2事务在修改fundserialcounter表,而当T1事务在修改fundserialcounter表的时候,T2事务还没有释放,这时T2事务需要处理fundreal表,T1事务还没有释放,这样相互等待就出现了死锁。
●实例2:
事务T1:
forcur_loopin(selecta.*fromfundrealawherea.fund_account>=‘10000’)loop
Updatefundreala
Seta.current_balane=a.current_balane+v_current_balane
Wherea.fund_account=cur_loop.fund_account
Anda.money_type=‘0’;
Updatefundserialcountera
Seta.serial_counter_value=a.serial_counter_value+1;
Wherea.serial_counter_no=1
Anda.branch_no=cur_loop.branch_no;
endloop;
事务T2:
Updatefundreala
Seta.current_balane=a.current_balane+v_current_balane
Wherea.fund_account=‘100001’
Anda.money_type=‘0’;
Updatefundserialcountera
Seta.serial_counter_value=a.serial_counter_value+1;
Wherea.serial_counter_no=1
Anda.branch_no=1;
当T1事务在修改fundreal表修改账号10000的时候并且修改了表fundserialcounter的branch_no字段为1的数据,T2事务在修改fundreal表修改账号100001的时候,而当T1事务在修改fundreal表账号100001的时候,T2事务还没有释放fundreal,这时T2事务需要处理fundserialcounter表,T1事务还没有释放fundserialcounter,这样相互等待就出现了死锁。
1.1.4.1死锁原理
当PMON(程序监控)后台进程检查到死锁之后,就会自动回滚导致死锁的命令,会产生如下错误:
ORA-00060:
deadlockdetectedwhilewaitingforresource.
并通知PMON首先检查到的哪一个进程发生了死锁(这是不能预测的),接收到死锁信息的进程必须决定释放回滚所做的其他修改,这样将使得另外一个进程继续下去,或者采取其他措施,如要求数据库管理员找到导致死锁的另外一个进程并进行杀死。
例如:
AlterSystemKillSession‘Sid,Serial#’;
2Oracle锁的查询
2.1涉及系统对象
2.1.1V$LOCK
查看当前系统中所有锁定的情况,主要字段内容如下
1.TYPE:
类型
说明
AD
ASMDiskAULock
AF
AdvisorFramework
AG
AnalyticWorkspaceGeneration
AK
GESDeadlockTest
AO
MultiWriterObjectAccess
AS
ServiceOperations
AT
AlterTablespace
AW
AnalyticWorkspace
BR
Backup/Restore
CF
ControlfileTransaction
CI
Cross-InstanceCallInvocation
CL
LabelSecuritycache
CM
ASMInstanceEnqueue
CT
BlockChangeTracking
CU
Cursor
DB
DbsDriver
DD
ASMLocalDiskGroup
DF
DatafileOnlineinRAC
DG
ASMDiskGroupModification
DI
GESInternal
DL
DirectLoaderIndexCreation
DM
DatabaseMount/Open
DN
Diskgroupnumbergenerator
DP
LDAPParameter
DQ
ASMRBALdoorbell
DR
DistributedRecovery
DS
DatabaseSuspend
DT
DefaultTemporaryTablespace
DV
DianaVersioning
DX
DistributedTransaction
E
LibraryCacheLock2
FA
ASMFileAccessLock
FB
FormatBlock
FC
DiskGroupChunkMount
FD
FlashbackDatabase
FG
ACDRelocationGateEnqueue
FL
Flashbackdatabaselog
FM
FileMapping
FR
DiskGroupRecovery
FS
FileSet/DictionaryCheck
FT
DiskGroupRedoGeneration
FU
DBFUS
G
LibraryCachePin2
HD
ASMDiskHeader
HP
QueuePage
HQ
HashQueue
HV
DirectLoaderHighWaterMark
HW
SegmentHighWaterMark
IA
Internal
ID
NID
IL
LabelSecurity
IM
Ktiblrlock
IR
InstanceRecovery
IS
InstanceState
IT
In-MemTempTableMetaCreation
IV
LibraryCacheInvalidation
IZ
INSTANCELOCK
JD
JobQueueDate
JI
MaterializedView
JQ
JobQueue
JS
JobScheduler
KK
KickInstancetoSwitchLogs
KM
Scheduler
KP
KuppProcessStartup
KT
SchedulerPlan
L
LibraryCacheLock1
MD
MaterializedViewLogDDL
MH
AQNotificationMailHost
ML
AQNotificationMailPort
MN
LogMiner
MR
MediaRecovery
MS
MaterializedViewRefreshLog
MW
MWINSchedule
N
LibraryCachePin1
OC
OutlineCache
OL
OutlineName
OQ
OLAPIHistories
PD
PropertyLock
PE
Parameter
PF
PasswordFile
PG
GlobalParameter
PH
AQNotificationProxy
PI
RemotePXProcessSpawnStatus
PL
TransportableTablespace
PM
ASMPSTSignalling
PR
ProcessStartup
PS
PXProcessReservation
PT
ASMPartnershipandStatusTable
PV
KSVslavestartup
PW
BufferCachePreWarm
Q
RowCache
RB
ASMRollbackRecovery
RF
DataGuardBroker
RM
GESResourceRemastering
RN
RedoLogNabComputation
RO
MultipleObjectReuse
RP
Resilver/Repair
RS
ReclaimableSpace
RT
RedoThread
SB
LogicalStandby
SC
SystemChangeNumber
SF
AQNotificationSender
SH
ActiveSessionHistoryFlushing
SI
StreamsTableInstantiation
SK
ShrinkSegment
SM
SMONSerialization
SQ
SequenceCache
SR
SynchronizedReplication
SS
SortSegment
ST
SpaceTransaction
SU
SaveUndoSegment
SV
SequenceOrdering
SW
SuspendWrites
TA
InstanceUndo
TB
SQLTuningBaseExistenceCache
TC
TablespaceCheckpoint
TD
KTFmaptableenqueue
TE
KTFbroadcast
TF
TemporaryFile
TL
LogLock
TM
DML
TO
TempObject
TQ
Queuetableenqueue
TS
TemporarySegment
TT
Tablespace
TW
Cross-InstanceTransaction
TX
Transaction
UL
User-defined
UN
UserName
US
UndoSegment
WA
AQNotificationWatermark
WF
AWRFlush
WL
BeingWrittenRedoLog
WP
AWRPurge
WS
LogWriterStandby
XH
AQNotificationNo-Proxy
XR
Quiesce/ForceLogging
XY
InternalTest
2.LMODE:
类型
说明
1
NULL
2
RS(RowShare)
3
RX(RowExclusive)
4
S(ShareTable)
5
SRX(ShareRowExclusive)
6
X(Exclusive)
3.REQUEST:
类型
说明
0
Success
1
Timeout(Thelockcouldnotbeobtainedwithinthespecifiednumberofseconds)
2
Deadlock(Inthiscase,anarbitrarysessionwillberolledback)
3
ParameterError
4
ThesessiondoesnotownthelockspecifiedbythelockIDorthelockhandle.
5
Invalidlockhandle.Thehandlewasnotfoundonthelocktable.
4.ID1:
TX状态下,等待锁的对象ID,TM状态下,回滚号码的十进制。
5.ID2:
TM:
0TX:
回滚槽重新使用的次数。
2.1.2V$SESSION
查看当前系统中的所有会话。
2.1.3V$SYSSTAT
包含对整个系统的所有重要的统计信息,可以使用V$SYSSTAT对每一个会话等待锁定的次数进行统计。
2.1.4V$ACCESS
查询当前被锁定的对象名称。
2.1.5V$SQLTEXT
查看当前会话的SQL脚本。
2.2锁查询脚本
2.2.1检查系统中锁的简单脚本
Selects.username,
s.sid,
l.type,
l.id1,
l.id2,
l.lmode,
l.request,
p.spidPID
Fromv$lockl,v$sessions,v$processp
Wheres.sid=l.sid
Andp.addr=s.paddr
Ands.usernameisnotnull
OrderByid1,s.sid,request;
用来获取用户SID、PID,锁的种类,锁的类型等信息。
2.2.2显示关于锁等待的会话
select/*rule*/
SN.Username,
M.Sid,
SN.Serial#,
A.Owner,
A.Object,
M.Type,
DECODE(M.Lmode,
0,
'None',
1,
'Null',
2,
'RowShare',
3,
'RowExcl.',
4,
'Share',
5,
'S/RowExcl.',
6,
'Exclusive',
M.Lmode,
LTRIM(TO_CHAR(M.Lmode,'990')))LKmode,
DECODE(M.Request,
0,
'None',
1,
'Null',
2,
'RowShare',
3,
'RowExcl.',
4,
'Share',
5,
'S/RowExcl.',
6,
'Exclusive',
M.Request,
LTRIM(TO_CHAR(M.Request,'990')))LRequest,
M.Id1,
M.Id2,
T.Sql_Textsql
fromV$SESSIONSN,GV$LOCKM,V$SQLTEXTT,V$ACCESSA
whereSN.Sid=A.Sid
andA.Owner<>'SYS'
andT.Address=SN.Sql_Address
andT.Hash_Value+0=SN.Sql_Hash_Value
and((SN.SID=M.SIDandM.Request!
=0)or
(SN.Sid=M.SidandM.Request=0andM.Lmode!
=4and
(M.Id1,M.Id2)in(selectS.Id1,S.Id2
fromGV$LOCKS
whereS.Request!
=0
andS.Id1=M.Id1
andS.Id2=M.Id2)))
orderbySN.Username,SN.Sid,T.Piece;
2.2.3显示数据库锁的信息(用户ID、OBJECT)
selectSN.Username,
M.Sid,
M.Type,
DECODE(M.Lmode,
0,
'None',
1,
'Null',
2,
'RowShare',
3,
'RowExcl.',
4,
'Share',
5,
'S/RowExcl.',
6,
'Exclusive',
M.Lmode,
LTRIM(TO_CHAR(M.Lmode,'990')))LKmode,
DECODE(M.Request,
0,
'None',
1,
'Null',
2,
'RowShare',