日期:2014-05-16 浏览次数:20542 次
一、概述
锁是协调对共享资源访问的一种机制。此处共享资源可能是数据行、表或者别的什么很多人都需要访问的资源。
Oracle数据库实现锁的机制跟别的数据库不同,在Oracle数据库中锁并不算的上是稀缺的资源,当然不合适的持有很多锁一定会降低程序的并发行和扩展性的。
二、锁定问题
考虑下这样一种场景,表T中有一行数据记录了一个人的信息,A和B两个客户端都要去修改,A和B都先获取了这个人的信息,然后A会修改地址,B会修改了证件号码。修改完后A先提交了修改,把用户的信息更新了一遍,提交事务后,B也进行了修改,提交。此时再去查看此人信息,发现A做的修改已经被覆盖,即相当于A没有进行任务操作。
解决问题的办法有两种:悲观锁定和乐观锁定
悲观锁定:当一个客户端要修改一条记录的时候, 就把该记录锁定,直到修改完提交了事务,如通过select * from T for update。这种办法当然有很一些问题了,在并发情况下对记录的锁定时间很长,如果是一些比较核心的资源,这种方式会极大降低并发度。在另外一些更新数量的场景下,情况变得更糟糕。
另外,如果是b/s应用模式,这问题就变得复杂了,每次请求一个事务,打开用户信息的时候,事务就已经完了,这种行上的锁也被释放了,等真正更新的时候已经没有了锁。
乐观锁定:我们在修改记录的时候,不像悲观锁定一样,一开始便锁定。而是在开始的时候记录一个关键的信息,等 真正要修改时候根据这个信息来判断我们在开始决定修改的时候到更新时候为止,有没有被别人更新过,如果更新过了,那么我们就提示修改失败,需要重新来修改。此处的关键信息可以是版本列,如时间戳;也可以是校验和,如该行一些关键字段或者所有字段值的hash/md5值,也可以作为一个虚拟列‘存放’hash/md5值。
但是另外考虑一种情况,在修改包含大量信息的表单的时候,用户辛辛苦苦录了半个小时的单据,在提交的时候说表单已经被修改了,你猜猜那会是什么样的情形?所以作为对悲观锁的一种扩展,我们可以在应用层级实现一种锁定,应用层负责添加、释放锁,并负责客户端处理异常终止、会话超时等情形下锁的释放,同时提供应用级锁定的管理功能,可以管理员手动释放锁。
三、锁
1)、DML锁
顾名思义就是执行dml语句时候加的锁,如update、delete、select、insert等。怎么分成tm和tx锁的?在oracle数据库中select语句是从来不加锁的,对于一个大表,你在一个会话中查询还没有完成的时候,可以在另外一个会话中把表给drop掉,第一个会话中的查询会一直进行到查完所有数据。
? a、TX锁
事务锁,属于行级锁,如果当前没有事务,则第一条修改表数据的sql语句将隐式的开启一个新事务,容易update、 delete、 insert语句,同时该事务会持有一个tx锁,这些语句修改的数据也将指向这把tx锁。如果已经有了事务,则直接指向已有的tx锁。
分别用sys和scott连接数据库,然后用sys查看scott持有的锁:
SQL> select sess.username,sess.sid,lck.type,lck.lmode from v$session sess left join v$lock lck on lck.sid = sess.sid where sess.username = upper('scott'); USERNAME SID TYPE LMODE --------------------- ---------- ---- ---------- SCOTT 132 AE 4
然后用scott更新emp的一条记录后再查询锁的信息:
?
SQL> select sess.username,sess.sid,lck.type,lck.lmode 2 from v$session sess 3 left join v$lock lck on lck.sid = sess.sid 4 where sess.username = upper('scott'); USERNAME SID TYPE LMODE ---------------------------- ---------- ---- ---------- SCOTT 132 AE 4 SCOTT 132 TM 3 SCOTT 132 TX 6??