有关"SELECT FOR UPDATE"的一些问题 .

本文详细介绍了如何使用PL/SQL的FORUPDATE命令处理Oracle数据库中的死锁问题,包括查看锁定情况、获取会话信息、杀掉锁定进程等步骤,并提供了具体SQL语句示例。

  相关问题:用PL SQL执行for update命令后死锁了解锁   
               删除掉v$locked_object当中的临时锁定
           for update 解锁

     首先我的问题,是,今天在PL/SQL当中用了SELECT FOR UPDATE语句,没有像做学问一样,找到问题,然后去看是谁的电脑锁住了,然后仔细的检查一次,没有那样,而且也不允许我那样子做。只有自己删掉锁session,然后继续工作。

     所谓只要自己积极主动的去解决问题,就没有多大的问题,当然,不是那种相当尖锐的难题,我只是指当下遇到的一些问题,工作中,每个行业遇到自己行业当中的难题,其实在所难免,不过解决起来,他们自有自己的一套,比如今天遇到的这个oracle的锁问题。

如果是为了解决这个问题,自己网上一搜索,一大把,而且相当客观和直接的解决了我的问题。

  1. --查看表对象的对象ID  
  2. select object_id from user_objects where object_name=upper('m2m_menu_node_cfg_tbl');  
  3. --查看锁定情况  
  4. select sid from v$lock where id1=74284;  
  5. --查看根据SID获得当前session信息  
  6. select SID,STATUS,SERIAL# from v$session where sid in(108,151);  
  7. --杀掉进程,记住这里的10862987,是一条数据的SID和SERIAL#,不过没关系,试试也知道了,情况就那几种,呵呵  
  8. alter system kill session '108,62987';  
  9. --  
  10. --命令行下,或过程execute immediate 'alter system kill session '||''''||108||','||151||'''';  
  11. ---------用上面的语句得到当前的锁定情况,用下面一句也行  
  12. --得到当前锁定情况  
  13. select object_name,machine,s.sid,s.serial#  
  14. from v$locked_object l,dba_objects o ,v$session s  
  15. where l.object_id = o.object_id and l.session_id=s.sid;  
  16. --查看当前再用的数据库的锁定情况  
  17. select * from v$locked_object  
  18. --杀掉进程,记住这里的10862987,  
  19. alter system kill session '108,62987';   


    以上介绍了两种方法,当然都可以解决问题,关于锁的问题和有哪些锁,我想,对于我只能够了解到那么多,在工作之余,能够学习得更深入,围绕自己的开发语言和自己说能用到的其他内容,比如C,不可能不接触到数据吧,只要有关于数据库,当然,不管是MYSQL,oracle,DB2,之类的,我们也不可能去一直研究他们,不过我们可以积累的研究他们,慢慢的学习过程当中,就会了解更多知识。


转自:http://blog.youkuaiyun.com/sebatinsky/article/details/5382229

<think>我们正在讨论SQL中的SELECT ...FOR UPDATE语句。根据引用,这个语句用于在事务中锁定选中的行,以防止其他事务修改这些行,直到当前事务结束(提交或回滚)。这主要用于需要保证数据一致性的场景,如银行转账或库存更新。 基本语法: STARTTRANSACTION; SELECT...FROM... WHERE... FORUPDATE;--执行更新操作COMMIT;或 ROLLBACK; 注意事项: 1.锁定范围:满足WHERE条件的所有行都会被锁定。若无WHERE条件,则锁定整个表(在InnoDB中,若没有索引可能导致表锁)。2.隔离级别:不同隔离级别会影响行为,通常建议使用REPEATABLE READ或以上。 3.死锁:多个事务相互等待锁可能导致死锁,需注意操作顺序。4.性能:锁定行会降低并发性能,应谨慎使用。5.存储引擎:仅支持行级锁的引擎(如InnoDB)有效,MyISAM不支持。示例(银行转账):假设有账户表(accounts): id| account_number |balance我们要从账户123向账户456转账100元。步骤:1.开始事务。2.使用SELECT... FORUPDATE锁定两个账户的行(注意:按固定顺序锁定以避免死锁,例如按id升序)。3.检查账户123余额是否足够。 4.更新账户123余额(减去100)。5.更新账户456余额(加上100)。 6.提交事务。 具体SQL:```sqlSTARTTRANSACTION; --锁定两个账户的行,按id顺序锁定以避免死锁SELECT* FROMaccounts WHEREaccount_numberIN (123,456) ORDERBY idFOR UPDATE; --检查账户123的余额SELECT balanceINTO @balanceFROM accountsWHERE account_number =123; --如果余额足够,则进行转账IF @balance >=100THENUPDATEaccounts SETbalance =balance -100WHERE account_number =123;UPDATE accountsSET balance= balance+100 WHEREaccount_number=456;END IF; COMMIT;``` 注意:在MySQL中,IF语句通常用于存储过程,如果不在存储过程中,可以使用程序逻辑判断。另一个示例(库存更新): 假设商品库存表(products): id| product_id| stock扣减商品ID为1001的库存1个: ```sqlSTART TRANSACTION;--锁定商品1001的行SELECT *FROM productsWHERE product_id =1001 FORUPDATE;--检查库存SELECT stockINTO @stockFROM productsWHERE product_id =1001;--如果库存足够,则扣减IF @stock >0THENUPDATE productsSET stock= stock-1 WHEREproduct_id=1001; ENDIF;COMMIT; ```重要提示:使用SELECT ...FOR UPDATE时,应尽量缩小锁定范围(使用精确的WHERE条件)并尽快提交事务,以减少锁竞争。相关问题: 1. SELECT... FORUPDATE在哪些情况下会导致表锁?2.如何避免使用SELECT ...FOR UPDATE时出现的死锁问题? 3. SELECT... FORUPDATE和 LOCK INSHAREMODE有什么区别?</think>### SELECT ... FOR UPDATE 的用法与示例 `SELECT ... FOR UPDATE` 是 SQL 中用于实现**行级锁**的关键语句,主要在事务中锁定选中的行,防止其他事务修改这些行,确保数据一致性。以下是详细说明: --- #### **核心作用** 1. **独占锁**:锁定查询到的行,禁止其他事务更新或删除(其他事务可读,取决于隔离级别) 2. **事务安全**:保证当前事务完成前,锁定数据不被篡改 3. **适用场景**: - 银行转账(防止并发修改余额) - 库存扣减(避免超卖) - 订单处理(防止重复操作) --- #### **基本语法** ```sql START TRANSACTION; -- 开启事务 SELECT column1, column2 FROM table_name WHERE condition FOR UPDATE; -- 锁定符合条件的行 -- 执行数据更新操作... UPDATE table_name SET column1 = value WHERE condition; COMMIT; -- 提交事务(释放锁) -- 或 ROLLBACK; -- 回滚事务(释放锁) ``` --- #### **关键注意事项** 1. **锁定范围**: - 精确 `WHERE` 条件 → 行级锁 - 无 `WHERE` 条件 → 锁整个表(慎用!) - 无索引字段 → 可能升级为表锁[^3] 2. **存储引擎**: - 仅支持行锁的引擎有效(如 **InnoDB**) - MyISAM 引擎无效(仅支持表锁)[^3] 3. **隔离级别影响**: - `REPEATABLE READ`(默认):锁定查询到的行 - `READ COMMITTED`:锁定实际更新的行[^1] 4. **死锁风险**: - 多事务循环等待锁会触发死锁 - 解决方案:按固定顺序操作资源(如按 ID 排序) --- #### **实际示例** ##### 场景:银行转账(保证余额一致性) ```sql START TRANSACTION; -- 锁定两个账户(按ID顺序避免死锁) SELECT * FROM accounts WHERE account_number IN (123, 456) ORDER BY id FOR UPDATE; -- 锁住账户123和456 -- 检查余额是否充足 SELECT balance FROM accounts WHERE account_number = 123; -- 执行转账(假设余额充足) UPDATE accounts SET balance = balance - 100 WHERE account_number = 123; UPDATE accounts SET balance = balance + 100 WHERE account_number = 456; COMMIT; ``` > **关键点**:锁定期间其他事务无法修改这两个账户的余额,防止透支[^4]。 --- ##### 场景:库存扣减(防止超卖) ```sql START TRANSACTION; -- 锁定商品ID=1001的行 SELECT stock FROM products WHERE product_id = 1001 FOR UPDATE; -- 检查库存 IF stock > 0 THEN UPDATE products SET stock = stock - 1 WHERE product_id = 1001; END IF; COMMIT; ``` --- #### **常见问题解决方案** 1. **死锁处理**: - 缩短事务执行时间 - 按固定顺序访问资源(如按主键排序) - 设置锁等待超时:`SET innodb_lock_wait_timeout=10;` 2. **性能优化**: - 避免全表扫描(确保 `WHERE` 条件用索引) - 最小化锁定时间(事务尽快提交) > **注意**:过度使用会导致并发性能下降,仅在必要时使用[^3]。 --- #### **与其他锁对比** | **语句** | **锁类型** | **其他事务能否读** | **其他事务能否写** | |------------------------|------------|-------------------|-------------------| | `SELECT ... FOR UPDATE`| 独占锁 | ✅ (MVCC) | ❌ | | `LOCK IN SHARE MODE` | 共享锁 | ✅ | ❌ | ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值