|
我们知道给资源上锁可以使我们串行化地访问资源,oracle为plsql开发人员提供了DBMS_SQL包用来管理USERL LOCK锁资源。这种锁可以使得多个session串行的执行某个存储过程,还可以用来排他的访问某个外部设备或服务,甚至可以检测事务的提交或回滚(提交或回滚时锁的释放)。
有人说我在java端调用db的存储过程,可以使用synchronized lock来串行的调用存储过程。那就不需要db lock呢?因为当java端应用服务器down的时候,存储过程已经在执行了,但是可能oracle session(RAC的db)并没有立即释放掉。当我们重启应用服务器后,其实后台的以前的存储过程还在执行,如果再次调用存储过程,这就无法保证存储过程的串行执行了。所以说存储过程的同步锁是必须放在Oracle db端的。
DBMS_LOCK包具有下面几个API,主要说明以下几个,其他的可以参考oracle相应文档,我们这里只用X锁(排他锁也称写锁)。
PROCEDURE DBMS_LOCK.ALLOCATE_UNIQUE

(lockname IN VARCHAR2

,lockhandle OUT VARCHAR2

,expiration_secs IN INTEGER DEFAULT 864000);
|
参数 |
描述 |
|
lockname |
锁的名称 |
|
lockhandle |
与该名称相对应的锁的唯一标识 |
|
expiration_secs |
这种名称到锁的映射的保存时间 |
当多个session用同样的名字lockname来获取唯一标识字符串时,不同的session用同样名字获取的lockhandle是相同的,lockname是最大128位的字符串,而且是大小写敏感的,锁的名字最好不要用"ORA$"打头,这种锁的名称是被oracle保留的名称。 DBMS_LOCK.ALLOCATE_UNIQUE执行完后就会commit所以不能被trigger调用。所有获得的映射都为存放在SYS用户 DBMS_LOCK_ALLOCATED视图中。
|
参数 |
描述 |
|
id |
锁的唯一标识 |
|
lockhandle |
由DBMS_LOCK.ALLOCATE_UNIQUE返回的handle |
|
lockmode |
锁的模式 |
|
timeout |
等待时间 |
|
release_on_commit |
COMMIT or ROLLBACK事务时是否释放锁 |
|
返回值 |
描述 |
|
0 |
成功申请到锁 |
|
1 |
超时 |
|
2 |
死锁 |
|
3 |
参数错误 |
|
4 |
已经拥有特定id或handle的锁 |
|
5 |
不合法的lockhandle |
用户定义的锁标识必须在 0 到 1073741823. 锁标识在范围2000000000 到 2147483647 被oracle公司预先保留。推荐用lockhandle的方法获得锁,因为锁的名称是比较容易辨别的,也是比较容易描述的。第一种方法不被oracle 推荐。
在共享服务器模式和分布式事务时我们最好把release_on_commit设置为true.
|
参数 |
描述 |
|
id |
锁的数字标识 |
|
lockhandle |
ALLOCATE_UNIQUE返回的锁的handle |
|
返回值 |
描述 |
|
0 |
成功 |
|
3 |
参数错误 |
|
4 |
并没有拥有特定的锁 |
|
5 |
不合法的lockhandle |
RELEASE 函数用来释放先前申请的锁。当锁不用时最好立即释放,这是很好的习惯。锁本身就是宝贵的资源,并且可以尽早释放被锁住的资源,而且可以有效地避免死锁。
如何使用这些api,很容易只要在我们的存储过程之前或者之后调用申请锁,释放锁(或者在事务提交或rollback的时候自动释放锁)就可以了,但这样也带来了存储过程代码的侵入性,每个存储过程都必须调用申请锁,释放锁。我们可以写一个wrapper把锁的申请和释放包裹起来。类似于模板模式。
[1] [2] 下一页 |