一.丢失更新
??? 所有多用户环境中存在丢失更新,丢失更新可以如下示例:
???
??????? 发生这种情况的原因:应用开发人员编写的程序时是这样的:更新一个特定的字段时,该记录的所有字段都会“刷新”(只是因为更新所有列更容易,这样就不用先得出哪些列已经修改,并且只更新那些修改过的列)。
?????? 避免这种情况可以用两种锁定策略:悲观锁定或乐观锁定。
二.悲观锁
????? 悲观锁定只用于有状态或有连接环境。
???? 在试图更新之前,从数据库查询这一行就锁定这一行。(因为我们很悲观,对于这一行能不能保持未改变很是怀疑)
??? select empno,ename,sal from scott.emp where deptno=10;
??
EMPNO? ENAME?? SAL
??? 7782??? CLARK??? 2450.00
??? 7839??? KING?????? 5000.00
??? 7934??? MILLER??? 1300.00
? 在SQLplus中模拟应用可能执行的绑定调用,可以利用下面命名:
?SQL> variable empno number
SQL> variable ename varchar2(20)
SQL> variable sal number
SQL> exec :empno :=7934; :ename :='MILLER'; :sal :=1300;
?
PL/SQL procedure successfully completed
?for update 锁定这一行
?The FOR
UPDATE
clause lets you lock the selected rows so that other users cannot lock or update the rows until you end your transaction. You can specify this clause only in a top-level SELECT
statement, not in subqueries.
?
锁定命令:
?SQL>? select empno,ename,sal from scott.emp
? 2? where empno=:empno and ename=:ename and sal=:sal
? 3? for update nowait;
EMPNO ENAME??????????? SAL
----- ---------- ---------
?7934 MILLER?????? 1300.00
试图对这行进行修改:
SQL>update scott.emp set ename='ML' where empno=7934;
进程耗在这,因为这行被你锁定了,在你结束你的事务之前,不能修改
查询锁定对象:
SELECT Do.Object_Name, Session_Id, Process, Locked_Mode
FROM V$locked_Object? Lo, Dba_Objects Do
WHERE Lo.Object_Id = Do.Object_Id;
OBJECT_NAM SESSION_ID PROCESS????? LOCKED_MODE
? ----------??????????? ---------- ? ? ? ? ?? ------------ ? ? ? ? ? -----------
??? EMP????????????? ?? 140??????????? ? ?? ? 3204:3008????????????? 3
提交事务,锁释放。之后可以进行更新
三.乐观锁
??? 乐观锁:把所有锁定都延迟到即将执行更新之前才做。换句话说,我们会修改信息而不需要锁。
?? (我们很乐观,认为数据不会被其他用户修改,因此,会等到最后一刻才去看想法对不对)
?? 实现乐观并发控制的有很多种;
(1)可以在应用中同时保留旧值和新值,然后再更新数据时使用如下语句,这是乐观锁的一种流行实现:
??? update table
?????? set column1 =:new_column1, column2 =:new column2,...
??? where primary_key=:primary_key
??? and column1 =:old_column1
??? and column2 =:old_column2
??? ........
?
?
? (2)使用一个特殊的列记录的"版本",这个列由数据库触发器或应用程序代码维护。
?例子: (先建一个表,然后插入数据,在更新时如果实现乐观锁)
?create table carleena.dept
( deptno number(2),
? dname? varchar2(14),
? loc??? varchar2(13),
? last_mod timestamp with time zone default systimestamp not null,
? constraint dept_pk primary key(deptno)?
)
插入数据
? insert into carleena.dept(deptno,dname,loc)
? select deptno,dname,loc
? from scott.dept;