数据库是多个用户使用的共享资源。为了保证数据的一致性,锁是实现数据库并发控制的一项非常重要的技术。事务在对数据对象进行操作之前,首先会向系统发送锁定请求。加锁后,事务对数据对象有了一定的控制权。在事务释放锁之前,其他事务不能对该数据对象进行操作。此数据对象执行更新操作。数据库包含两种基本类型的锁:独占锁(X锁)和共享锁(ShareLocks,S锁)。这两种基本的锁类型用于控制数据库事务的并发性。ORACLE数据库根据保护对象的不同,将Oracle数据库锁分为以下几类:DML锁(数据锁,数据锁),用于保证并发情况下的数据完整性;DDL锁(dictionarylocks,字典锁),用于保护数据库对象的结构,如表、索引等的结构定义;内部锁和闩锁(internallocksandlatches),保护数据库的内部结构。这里只讨论DML锁。在Oracle数据库中,DML锁主要包括TM锁和TX锁,其中TM锁称为表级锁,TX锁称为事务锁或行级锁。Oracle在执行DML语句时,系统会自动为要操作的表申请一个TM类型的锁。获得TM锁后,系统自动申请一个TX类型的锁,并设置实际锁定数据行的锁标志。数据行上只有X锁(独占锁)。在Oracle数据库中,当一个事务发起一个DML语句时,会获得一个TX锁,这个锁一直保持到事务提交或回滚。当两个或多个会话对表中的同一条记录执行DML语句时,第一个会话锁定该记录,其他会话处于等待状态。当第一个session提交后,TX锁就被释放,其他session就可以加锁了。Oracle数据库在等待TX锁时,如果不及时处理,往往会导致Oracle数据库挂起或死锁,导致ORA-00060错误,导致应用程序长期无响应和大量交易失败。TX锁等待如何处理当数据库发生enq:TX-rowlockcontention行级锁等待时,可以查询v$session.blocking_session列或者v$lock视图找到阻塞源,快速恢复通过查杀阻塞源业务恢复正常。如何定位TXLockSpecificRowData在某些情况下,用户想知道哪些特定数据经常发生TXlockwaiting。下面展示如何获取TX锁的具体行数据。1、SQL语句中没有使用绑定变量。会话1:SQL>updatet1setb=10wherea=3;会话2:SQL>updatet1setb=99wherea=3;这时候可以通过v$sql和v$session的联合查询来获取具体的Row数据:selectsql_textfromv$sqla,v$sessionbwherea.sql_id=b.sql_idandb.event='enq:TX-rowlockcontention';可以知道t1表中a=3行有一个TXlockwaiting2.SQL语句VariableSession1中使用了Binding:SQL>variablev_anumber;SQL>exec:v_a:=3;SQL>updatet1setb=10wherea=:v_a;Session2:SQL>variablev_anumber;SQL>exec:v_a:=3;SQL>updatet1setb=99wherea=:v_a;通过v$sql和v$session联合查询:selectsql_textfromv$sqla,v$sessionbwherea.sql_id=b.sql_idandb.event='enq:TX-rowlockcontention';可以发现结果是带有变量的SQL,无法定位到具体的行。这时可以通过如下SQL获取具体的锁行信息:SELECTrow_wait_obj#,row_wait_file#,row_wait_block#,row_wait_row#FROMv$sessionWHEREevent='enq:TX-rowlockcontention';这四列代表的含义如下:object_id为14255的object,等待发生在4号文件的block133的第一行数据(数据从0行开始)。根据object_id获取表名和data_object_idSQL>selectowner||'.'||object_nametab_name,data_object_idfromdba_objectswhereobject_id=14255;TEST.T114296然后通过函数ROWID_CREATE转换得到ROWIDSQL>selectdbms_rowid.ROWID_CREATE(1,14296,4,133,1)fromdual;---14296指的是dba_objects.data_object_idAAADfYAAEAAAACFAABSQL>select*fromTEST.T1whererowid='AAADfYAAEAAAACFAAB';AB34等待找到锁,就是这一行数据。注意:这种方法同样适用于不使用bind变量的情况如何避免TX锁等待避免使用selectforupdate查询数据修改数据后,修改大量数据后尽快提交,避免在高峰期营业时间;如果可能,拆分成多个事务,批量修改提交(dbms_rowid.ROWID_CREATE函数)关于dbms_rowid.ROWID_CREATE函数,需要注意的是OBJECT_NUMBER的输入值为dba_objects.data_object_id。FUNCTIONROWID_CREATERETURNSROWIDArgumentNameTypeIn/OutDefault?------------------------------------------------------------------ROWID_TYPENUMBERINOBJECT_NUMBERNUMBERINRELATIVE_FNONUMBERINBLOCK_NUMBERNUMBERINROW_NUMBERNUMBERIN
