for update 与where current of的问题

本文详细解释了Oracle中的FORUPDATE和FORUPDATEOF的作用,并通过实例展示了它们在不同情况下的使用方法。包括如何查看效果、与SQL等待机制的关系、NOWAIT与WAIT的区别,以及FORUPDATE在多表连接时的特性和与FORUPDATEOF的对比。同时,通过PL/SQL示例演示了如何在循环中使用FORUPDATEOF进行锁定操作。
部署运行你感兴趣的模型镜像

在刚学oracle时一直不明白for update 的作用,今天考试又遇到郁闷半天,所以加以整理。

1>首先for update是对表的行进行锁定。锁定就好比我们学java Thread那一章时,为某个线程的run()枷锁,当实例化出来多个线程时,它必须一个线程全部执行完后,释放锁其他线程才有机会运行。本文for update功能上一样,就是为一个select语句枷锁,这样在对这个表进行update ,delete时就会处于等待状态,等待selec执行commit或rollback(相当于线程释放锁)后,才可以对表进行更改或删除。

怎样看效果呢?1:首先在“运行”-->cmd-->连接数据库 执行select * from emp for update

2 :然后在打开另一个窗口(就相当于创建了两个用户):“运行”-->cmd-->连接数据库 执行update emp set sal=100;你会发现它不执行了。

2>那马for update与for update of 有神马区别呢?

1.select * from Table1 for update 锁定表的所有行,只能读不能写

  2 select * from Table1 where id = 1 for update 只锁定id=1的行

  3 select * from Table1 a join Table2 b on a.id=b.id for update 锁定两个表的所有记录

  4 select * from Table1 a join Table2 b on a.id=b.id where a.id = 10 for update 锁定两个表的中满足条件的行

  5. select * from Table1 a join Table2 b on a.id=b.id where a.id = 10 for update of a.id 只锁定Table1中满足条件的行

  for update 是把所有的表都锁点 for update of 根据of 后表的条件锁定相对应的表

3>关于oracle:select...for update of columns

按照1>步骤执行1:select * from emp for update of sal在另一个窗口中执:2:update emp set job='clerk' where empno=10;按照2>的的思维我们可能认:“1”只锁定了emp表的sal列,其实不然当运行“2”时,我们发现它任然不执行,所以for update of columns 是锁定的与sal相关的行。那么for update 与for update of 有神吗区别呢?区别在于多表连接时;

例如:

按照1>分别执行 select ename,dname from emp,dept where emp.deptno=dept.deptno for update;

另一窗口执行:update dept set dname='haha'where deptno=10;我们发现dept表不能更改

当我们在 select ename,dname from emp,dept where emp.deptno=dept.deptno for update of sal;时

update dept set dname='haha'where deptno=10;可以在执行了。

由此我们可以综结出:for update of columns 用在多表连接锁定时,可以指定要锁定的是哪几张表,而如果表中的列没有在for update of 后面出现的话,就意味着这张表其实并没有被锁定,其他用户是可以对这些表的数据进行update操作的。这种情况经常会出现在用户对带有连接查询的视图进行操作场景下。用户只锁定相关表的数据,其他用户仍然可以对视图中其他原始表的数据来进行操作。

4>关于nowait与wait

SELECT ... FOR UPDATE [OF column_list][WAIT n|NOWAIT][SKIP LOCKED];
1:其中:

  OF 子句用于指定即将更新的列,即锁定行上的特定列。

NOWAIT不进行等待,如果这条语句的锁没被释放,则会直接报出:系统资源正忙
  WAIT 子句指定等待其他用户释放锁的秒数,防止无限期的等待。
  “使用FOR UPDATE WAIT”子句的优点如下:
  1防止无限期地等待被锁定的行;
  2允许应用程序中对锁的等待时间进行更多的控制。
  3对于交互式应用程序非常有用,因为这些用户不能等待不确定
  4 若使用了skip locked,则可以越过锁定的行,不会报告由wait n 引发的‘资源忙’异常报告:

2:现在执行如下操作:

在plsql develope中打开两个sql窗口,在1窗口中运行sql
select * from t where a='1' for update;
在2窗口中运行sql1
1. select * from t where a='1'; 这一点问题也没有,因为行级锁不会影响纯粹的select语句
再运行sql2
2. select * from t where a='1' for update; 则这一句sql在执行时,永远处于等待状态除非窗口1中sql 被提交或回滚。
如何才能让sql2不等待或等待指定的时间呢? 我们再运行sql3
3. select * from t where a='1' for update nowait; 则在执行此sql时,直接报资源忙的异常。
若执行 select * from t where a='1' for update wait 6; 则在等待6秒后,报 资源忙的异常。如果我们执行 sql4
4. select * from t where a='1' for update nowait skip Locked; 则执行sql时,即不等待,也不报资源 忙异常。
现在我们看看执行如下操作将会发生什么呢?
在窗口1中执行:
select * from t where rownum<=3 nowait skip Locked;
在窗口2中执行:
select * from t where rownum<=6 nowait skip Locked;
select for update 也就如此了吧,insert、update、delete操作默认加行级锁,其原理和操作与select for update并无两样。
select for update of,这个of子句在牵连到多个表时,具有较大作用,如不使用of指定锁定的表的列,则所有表的相关行均被锁定,若在of中指定了需修改的列,则只有与这些列相关的表的行才会被锁定.

二:

1:

如果你想删除或者更新被Select For Update引用的记录,你可以使用Where Current Of语句

DECLARE
  CURSOR CUR_NAME IS
    SELECT * FROM EMP WHERE deptno=10 FOR UPDATE OF sal;
BEGIN
  FOR REC IN CUR_NAME LOOP
    UPDATE EMP SET sal =100 ;
  END LOOP;
END;
上述pl/sql执行过之后我们发现emp表中所有的sal列数据都被更改,此时我们只想更改跟游标对应的行,所以我们又到where current of执行游标遍历时的当前行就好像for(int i=0;i++;i<10){}where current of与“i”的功能相似。所以当我们想执行游标影响的行时,上我们可以把上面pl/sql快改为:

DECLARE
  CURSOR CUR_NAME IS
    SELECT JOB FROM EMP WHERE deptno=10 FOR UPDATE OF sal;
BEGIN
  FOR REC IN CUR_NAME LOOP
    UPDATE EMP SET sal =100 WHERE CURRENT OF CUR_NAME;
  END LOOP;
END;

不知道你们明白不,反正我是明白了。哈哈





您可能感兴趣的与本文相关的镜像

Facefusion

Facefusion

AI应用

FaceFusion是全新一代AI换脸工具,无需安装,一键运行,可以完成去遮挡,高清化,卡通脸一键替换,并且Nvidia/AMD等显卡全平台支持

在PL/SQL中,`FOR UPDATE` 游标和 `WHERE CURRENT` 游标是用于在处理数据时控制并发访问和精确更新或删除特定行的重要机制。 ### `FOR UPDATE` 游标 `FOR UPDATE` 子句用于在打开游标时锁定游标结果集合所对应的数据库表中的数据行。当执行带有 `FOR UPDATE` 选项的 `SELECT` 语句(即打开游标)时,会将查询结果放入工作区,并且指针指向工作区的首部,同时锁定这些数据行,防止其他会话在当前事务提交或回滚之前对这些行进行修改或删除操作,从而保证数据的一致性和完整性 [^3]。 示例代码如下: ```plsql -- 声明一个带有 FOR UPDATE 的游标 DECLARE CURSOR c_employees IS SELECT employee_id, salary FROM employees WHERE department_id = 10 FOR UPDATE; v_emp_id employees.employee_id%TYPE; v_salary employees.salary%TYPE; BEGIN -- 打开游标 OPEN c_employees; -- 循环处理游标结果 LOOP FETCH c_employees INTO v_emp_id, v_salary; EXIT WHEN c_employees%NOTFOUND; -- 对当前行进行更新操作 UPDATE employees SET salary = salary * 1.1 WHERE employee_id = v_emp_id; END LOOP; -- 关闭游标 CLOSE c_employees; -- 提交事务 COMMIT; END; ``` 在上述代码中,`FOR UPDATE` 子句确保在打开游标时锁定 `employees` 表中 `department_id` 为 10 的所有行,防止其他会话在当前事务完成之前修改这些行。 ### `WHERE CURRENT` 游标 `WHERE CURRENT OF` 子句用于在更新或删除操作中引用当前游标所指向的行。它只能 `FOR UPDATE` 子句一起使用,因为只有在使用 `FOR UPDATE` 锁定了行之后,才能精确地定位到当前游标所指向的行进行更新或删除操作 [^3]。 示例代码如下: ```plsql -- 声明一个带有 FOR UPDATE 的游标 DECLARE CURSOR c_employees IS SELECT employee_id, salary FROM employees WHERE department_id = 10 FOR UPDATE; v_emp_id employees.employee_id%TYPE; v_salary employees.salary%TYPE; BEGIN -- 打开游标 OPEN c_employees; -- 循环处理游标结果 LOOP FETCH c_employees INTO v_emp_id, v_salary; EXIT WHEN c_employees%NOTFOUND; -- 使用 WHERE CURRENT OF 子句更新当前行 UPDATE employees SET salary = salary * 1.1 WHERE CURRENT OF c_employees; END LOOP; -- 关闭游标 CLOSE c_employees; -- 提交事务 COMMIT; END; ``` 在上述代码中,`WHERE CURRENT OF c_employees` 子句确保每次更新操作都是针对当前游标所指向的行进行的,避免了手动指定条件来定位行的复杂性。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值