在多用户数据库系统中,锁非常重要。用户可以锁定一个对象,可以防止其他用户修改锁定的对象。多个并发用户访问数据库数据的情况下,为了保证数据的完整性,锁是必需的。
一、什么是锁
锁作为关联到数据项的对象。程序可以显示对数据加锁,数据库系统也可以隐式的对对象进行加锁。锁描述事务所操作对象的一种状态信息。
二、SinoDB的锁类型
SinoDB的锁类型有以下四种:
Shared locks: 共享锁,多个用户可以同时读取相同的记录;
Exclusive locks: 排他锁,同一时间仅仅有一个用户可以读取相同的记录;
Promotable (Update) lock: 提升锁,可以从升级 (从共享锁提升为排他锁) 或者降级 (反之亦然);
Intent lock: 专一锁,是一种表级锁,标识在该表上有一个游标在读取数据。
1.共享锁(lock-S)
如果一个对象上没有排他锁,则共享锁可以加在该对象上,防止其他事务更新数据,但同时,其他事务可以读取该数据 (其他事务可以加共享锁),多个事务可以在同一个对象上加多个共享锁。
2.排他锁 (lock-X)
如果记录上没有任何锁,排他锁才可以加在该对象上,一旦在记录上加了排他锁,则不能在该记录上增加任何锁了,直至锁释放防止其他事务读取和更修数据。
3.更新锁 (lock-U)
更新锁由cursors 含有 ‘for update’ 选项执行时产生的 ,只能在没有排他锁或者更新锁的记录上加更新锁,当锁定的记录真正执行的时候,更新锁将提升为排他锁。
图12.2.2-3
4.专一锁 (lock-IX or IS)
由SinoDB自动分配,如果一条记录上的记录被更新,一个排他锁将分配在该记录上,同时将该记录的表上自动加上专一锁,这能保证没有session可以在该表上增加排他锁,只要该表中有记录被增加了排他锁。
三、锁的有效期
程序控制数据库锁的有效期:
当SinoDB数据库关闭后,锁将被释放,根据数据库是否使用了事务的情况,表锁的有效期不同,如果数据没有使用事务(没有事务日志,也不使用commit work语句),显示对一个表lock,当执行unload table时,锁将被释放;当数据库使用了事务,事务结束时,将释放事务所有的锁 table, row, page, and index locks。
四、锁的粒度
1.在SinoDB数据库中, 我们可以按如下粒度进行加锁:
一般来讲,锁的粒度越大,并发性就越低,但是程序控制将越简单。
图12.2.4
2.什么情况下采用不同粒度的锁才有效、优?
1)Database-level locks:
数据库管理活动,比如: imports 和 exports,Ex: DATABASE database_name EXCLUSIVE
2)Table-level locks:
当整个表或者表的大部分数据需要更新,加表级锁效率高:LOCK TABLE tab1 IN EXCLUSIVE MODE,LOCK TABLE tab2 IN SHARE MODE,To unlock: UNLOCK TABLE tab1;
以下语句将隐式的对表加锁,直到事务结束后释放:
ALTER FRAGMENT
ALTER INDEX
ALTER TABLE
CREATE INDEX (if not using ONLINE keyword)
DROP INDEX (if not using ONLINE keyword)
RENAME COLUMN
RENAME TABLE
3.不同粒度锁在何时确定?
页级锁:当按数据物理顺序进行访问和更新时,页级锁效率高,修改锁模式为页级锁:ALTER TABLE tab1 LOCK MODE PAGE;
PAGE锁模式是数据库默认的表锁模式,默认锁模式参数 (ONCONFIG) 文件参数 DEF_TABLE_LOCKMODE.
行级锁:OLTP 事务采用行级锁,效率高
Table must have lock mode ROW:
CREATE TABLE tab1 (col1...) LOCK MODE ROW;
ALTER TABLE tab1 LOCK MODE (ROW);
4、哪一种锁粒度是优的呢?
锁粒度取决于事务本身的特点,当更新表中相对较小一部分数据的时候,采用行级锁将获取好的性能无论如何, 数据库会发生锁益处的情况。如果一个事务只访问表中一小部分数据,那就采用行级锁。如果一个事务频繁的访问整个表的数据,设置更粗的粒度,比如表级锁。如果更新数据库中大部分表的大部分数据的情况下, 采用数据库级别的锁。
SinoDB默认的锁模式为页级锁 :
ALTER TABLE table_name LOCK MODE (ROW);
ONCONFIG 参数 DEF_TABLE_LOCKMODE设置默认锁模式
查看表锁模式
oncheck –pt dbname:tablename
dbschema –d dbname –t tablename -ss
五、设置锁模式
不等待锁的释放 (默认),如果数据库对象被锁,则立即返回错误,
Ex:-244: Could not do a physical-order read to fetch the next row
107: ISAM error: record is locked
SET LOCK MODE TO NOT WAIT;
一直等待锁的释放,一个事务可能发生死锁和挂住,等待资源的释放SET LOCK MODE TO WAIT;在锁释放前,等待 n 秒直到等待N秒后,如果锁一直没有释放将返回锁等待超时错误信息,Ex: SET LOCK MODE TO WAIT 20;
六、死锁
当2个sessions加锁并且需要获取彼此之间的锁,将发生死锁
Example:
过程 A 等待过程B 释放资源
过程 B 等待过程A 释放其他的资源
过程A 等待 B ,而B又等待A …
死循环需要被中断
SinoDB 自动处理死锁:
在分配一个新锁前,SinoDB扫描内部的锁信息表,如果检测到死锁发生的条件,向应用程序发出ISAM error code 143。锁大等待时间通过ONCONFIG 参数 DEADLOCK_TIMEOUT设定。SinoDB使用DEADLOCK_TIMEOUT 作为来确定死锁的发生的一个条件。
图12.2.6
七、锁的监控与管理
监控session的隔离级别:
使用: onstat –g sql 或者 onstat –g ses
查看sid的详细信息: onstat –g sql sid
查看用户进程锁等待情况
使用: onstat –u
查看锁使用和等待情况:
使用: onstat -k
监控数据库事务及其状态:
使用: onstat -x
表被锁
ISAM error: key value locked
查询表的在数据库中的内部表号
select hex(partnum) from systables where tabname="test_lock";
返回值为:0x004000D4
查找上锁的用户线索
onstat -k|grep 4000D4 -i
45228970 0 985c8638 452288f0 HDR+IX 4000d4 0 0
45228a70 0 985c8638 45228970 HDR+X 4000d4 101 0 U
查找用户线索对应的会话
onstat -u|grep 985c8638
address flags sessid user tty wait tout locks nreads nwrites
985c8638 Y-BP--- 41 SinoDB - 9a2a0328 0 3 0 0
查看事务及锁的情况
onstat -x|grep 985c8638
找到相应的session 及SQL
onstat -g ses 41
杀掉session
onmode -z 41