一.悲观锁
当用户想要修改一条数据时,根据键盘上的输入的数据,应用将提供绑定变量的值,然后重新利用这些绑定的变量的值作为过滤条件去查询这一行,这一次会锁定这一行,不允许其他会话更新。
在试图更新前就把记录锁住了,我们很悲观,对于这一行能不能保持未改变很是怀疑。
注意:
1.如果在查询这条数据和锁这条数据之间,有人做了修改,那么就会得到0行,说明屏幕上的数据是过时的。
2.如果在查寻这条数据时另一个用户正在更新,那么会得到ORA-00054:resource busy。
应用范围:仅用于有状态或有连接的环境,也就是说你的应用和数据库有一条持续的连接,而且至少再事务生存期中只有你一个人使用这条连接。c/s模式。
因为根据屏幕的输入应用要反查数据库,看对应的数据有没有变化,没变化就加锁,在对这行的更新提交了后才释放锁,这个过程要求连接是连续的。
悲观锁的实现:
SQL> variable empno number
SQL> variable enam e vachar2(20)
SQL> variable ename varchar2(20)
SQL> variable sal number
SQL> exec :empno :=7934; :ename :='MILLER'; :sal :=1300;
--应用根据屏幕的输入绑定变量(empno,ename,sal)
select empno,ename,sal from emp where empno =:empno and decode(ename,:ename,1)=1 and decode(sal,:sal,1)=1 for update nowait
--反查数据库看相应的数据利用应用最初绑定的变量的值能查到不,如果能查到就给这行数据加锁。
update emp set ename= :ename,sal=:sal where empno=:empno;
commit;
--执行更新,释放锁。
二.乐观锁
乐观锁的实现(使用版本列的乐观锁定):
一.查询出要更新的字段的值,这里与悲观锁定有两个不同的地方:1.在表里多了一个字段(last_mod用于记录行的版本,如果有更新他业会更新)2.查处记录然后绑定变量但不锁定此行。
SQL> variable deptno number
SQL> variable dname varchar2(14)
SQL> variable loc varchar2(13)
SQL> variable last_mod varchar2(50)
SQL>
SQL> begin
2
:deptno :=10;
3
select dname,loc,to_char(last_mod,'DD-MON-YYYY HH.MI.SSXFF AM TZR')
4
into :dname,:loc,:last_mod
5
from dept
6
where deptno =:deptno;
7
end;
8
/
二.执行以下语句更新,要是更新一行的话说明在这个会话更新前没有人对此记录进行更新,这里主要靠第4行来验证记录是否被更新;但如果更新了0行,说明在此会话查询出记 录但在修改记录前有会话对此记录做了修改(也利用此逻辑更新的),并将last_mod=systimestamp,所以last_mod =to_timestamp_tz(:last_mod,'DD-MON-YYYY HH.MI.SSXFF AM TZR')条件不满足。
SQL> update dept
2
set dname=initcap(:dname),last_mod=systimestamp
3
where deptno =:deptno
4
and last_mod =to_timestamp_tz(:last_mod,'DD-MON-YYYY HH.MI.SSXFF AM TZR');
三。但是如果执行更新失败的话,应该怎么办呢。oracle推荐由存储过程来维护last_mod这一字段,更新返回0行时,抛给客户一个异常,让客户知道更新失败了。
乐观锁的实现(使用校验和的乐观锁定ORA_HASH):
一.查询要修改的行,并且算出这一行的散列值,并绑定在:hash。
SQL>
variable deptno number
SQL> variable dname varchar2(14)
SQL> variable loc varchar2(13)
SQL> variable hash number
SQL> begin
2
select deptno,dname,loc,
3
ora_hash(dname || '/' || loc) hash
4
into :deptno,:dname,:loc,:hash
5
from dept
6
where deptno=10;
7
end;
8
/
二。更新时检查这一行的散列值更更新之前查询出来的散列值是否一样。
SQL> exec :dname:=lower(:dname);
PL/SQL procedure successfully completed.
SQL> update dept
2
set dname=:dname
3
where deptno=:deptno and ora_hash(dname || '/' || loc) =:hash
4
/
1 row updated.
当用户想要修改一条数据时,根据键盘上的输入的数据,应用将提供绑定变量的值,然后重新利用这些绑定的变量的值作为过滤条件去查询这一行,这一次会锁定这一行,不允许其他会话更新。
在试图更新前就把记录锁住了,我们很悲观,对于这一行能不能保持未改变很是怀疑。
注意:
应用范围:仅用于有状态或有连接的环境,也就是说你的应用和数据库有一条持续的连接,而且至少再事务生存期中只有你一个人使用这条连接。c/s模式。
悲观锁的实现:
SQL> variable empno number
SQL> variable enam e vachar2(20)
SQL> variable ename varchar2(20)
SQL> variable sal number
SQL> exec :empno :=7934; :ename :='MILLER'; :sal :=1300;
--应用根据屏幕的输入绑定变量(empno,ename,sal)
select empno,ename,sal from emp where empno =:empno and decode(ename,:ename,1)=1 and decode(sal,:sal,1)=1 for update nowait
--反查数据库看相应的数据利用应用最初绑定的变量的值能查到不,如果能查到就给这行数据加锁。
update emp set ename= :ename,sal=:sal where empno=:empno;
commit;
--执行更新,释放锁。
二.乐观锁
乐观锁的实现(使用版本列的乐观锁定):
SQL> variable deptno number
SQL> variable dname varchar2(14)
SQL> variable loc varchar2(13)
SQL> variable last_mod varchar2(50)
SQL>
SQL> begin
二.执行以下语句更新,要是更新一行的话说明在这个会话更新前没有人对此记录进行更新,这里主要靠第4行来验证记录是否被更新;但如果更新了0行,说明在此会话查询出记 录但在修改记录前有会话对此记录做了修改(也利用此逻辑更新的),并将last_mod=systimestamp,所以last_mod =to_timestamp_tz(:last_mod,'DD-MON-YYYY HH.MI.SSXFF AM TZR')条件不满足。
三。但是如果执行更新失败的话,应该怎么办呢。oracle推荐由存储过程来维护last_mod这一字段,更新返回0行时,抛给客户一个异常,让客户知道更新失败了。
乐观锁的实现(使用校验和的乐观锁定ORA_HASH):
SQL>
SQL> variable dname varchar2(14)
SQL> variable loc varchar2(13)
SQL> variable hash number
SQL> begin
二。更新时检查这一行的散列值更更新之前查询出来的散列值是否一样。
SQL> exec :dname:=lower(:dname);
PL/SQL procedure successfully completed.
SQL> update dept
1 row updated.