Oracle的Select For Update语句可以实现在读取数据后马上锁定相关资源,防止被其他session修改数据的目的。也就是我们常常谈到的“悲观锁定”(现实应用开发中,使用悲观锁定的情况少之又少,也许是因为乐观锁定的实现更加灵活和便捷的缘故)。
这个小文儿做一个小小的实验,来看看Select For Update语句实现的行级锁定
1.创建实验表table_sfu,并初始化三条数据
sec@ora10g> create table table_sfu (a number);
Table created.
sec@ora10g> insert into table_sfu values (1);
1 row created.
sec@ora10g> insert into table_sfu values (2);
1 row created.
sec@ora10g> insert into table_sfu values (3);
1 row created.
sec@ora10g> commit;
Commit complete.
sec@ora10g> select * from table_sfu;
A
----------
1
2
3
2.使用Select For Update语句得到第一条数据
sec@ora10g> select * from table_sfu where a = 1 for update;
A
----------
1
3.查看一下现在系统中的锁定情况,152会话(即上面语句所在的会话)获得了一个TX锁和一个TM锁了,锁定的表就是TABLE_SFU
sec@ora10g> @lock
lock lock
holder holder lock lock request blocked
username sessid SERIAL# type id1 id2 mode mode BLOCK sessid
-------- ------- ------- ---- ------ ---- ---- ------- ----- -------
SEC 152 14985 TM 15396 0 3 0 0
SEC 152 14985 TX 327722 1790 6 0 0
164 1 TS 3 1 3 0 0
165 1 CF 0 0 2 0 0
165 1 RS 25 1 2 0 0
165 1 XR 4 0 1 0 0
166 1 RT 1 0 6 0 0
7 rows selected.
sec@ora10g> col OWNER for a6
sec@ora10g> col OBJECT_NAME for a10
sec@ora10g> select OWNER,OBJECT_NAME,OBJECT_ID,OBJECT_TYPE from dba_objects where object_id = '15396';
OWNER OBJECT_NAM OBJECT_ID OBJECT_TYPE
------ ---------- ---------- -------------------
SEC TABLE_SFU 15396 TABLE
4.另外新打开一个session,执行以下修改任务
sec@ora10g> update table_sfu set a = 100 where a = 1;
OK,效果出现了,这里出现了“锁等待”现象,原因就是因为在第一个session中使用Select For Update语句锁定了第一行数据,不允许其他的session对它修改。
5.这时系统中锁定情况如下,可以看到第一个session(session id是152)会话锁定了第二个session(session id是145)会话的事务
sec@ora10g> @lock
lock lock
holder holder lock lock request blocked
username sessid SERIAL# type id1 id2 mode mode BLOCK sessid
-------- ------- ------- ---- ------ ---- ---- ------- ----- -------
SEC 145 11388 TM 15396 0 3 0 0
SEC 152 14985 TM 15396 0 3 0 0
SEC 152 14985 TX 327722 1790 6 0 1 145
164 1 TS 3 1 3 0 0
165 1 CF 0 0 2 0 0
165 1 RS 25 1 2 0 0
165 1 XR 4 0 1 0 0
166 1 RT 1 0 6 0 0
8 rows selected.
6.因为仅仅是锁定了第一条数据,所以其他记录可以顺利的进行修改,如下
sec@ora10g> update table_sfu set a = 200 where a = 2;
1 row updated.
sec@ora10g> commit;
Commit complete.
7.解锁方式:commit或rollback后即完成锁定的接触
8.反过来思考一下,如果Select For Update与要锁定的行已经在其他session中完成了修改,再执行回出现什么效果呢?这个很显然,同样的会出现“锁等待”的现象,不过我想强调的是,这里可以使用nowait和wait选项来进行“探测”待锁定行是否可被锁定
实验效果如下:
第一个session:
sec@ora10g> update table_sfu set a = 100 where a = 1;
1 row updated.
第二个session:
sec@ora10g> select * from table_sfu where a = 1 for update;
此处是“锁等待”效果
sec@ora10g> select * from table_sfu where a = 1 for update nowait;
select * from table_sfu where a = 1 for update nowait
*
ERROR at line 1:
ORA-00054: resource busy and acquire with NOWAIT specified
这里提示了错误,原因就是已经“探测”到该行已经被别的事务锁定,这里无法对其进行锁定操作。
sec@ora10g> select * from table_sfu where a = 1 for update wait 3;
select * from table_sfu where a = 1 for update wait 3
*
ERROR at line 1:
ORA-30006: resource busy; acquire with WAIT timeout expired
这里提示的错误内容与上面的一样,不过这里wait 3表示,我等你三秒的时间,如果三秒过后还无法锁定资源,就报错。
9.更进一步,请参考Oracle官方文档中相关的描述
《for_update_clause ::=》
http://download.oracle.com/docs/cd/B19306_01/server.102/b14200/statements_10002.htm#i2126016
语法格式:
FOR UPDATE
[ OF [ [ schema. ]
{ table | view } . ]column
[, [ [ schema. ]
{ table | view } . ]column
]...
]
[ NOWAIT | WAIT integer ]
同上述连接,搜索关键字“for_update_clause”可以得到每个选项的解释信息
《Using the FOR UPDATE Clause: Examples 》
http://download.oracle.com/docs/cd/B19306_01/server.102/b14200/statements_10002.htm#i2130052
10.小结
上面的小实验展示了一下Select For Update行级锁定的效果,Oracle的锁定机制还是非常的灵活的,基于这个锁定可以实现“悲观锁定”。
分享到:
相关推荐
`FOR UPDATE`是Oracle中用于实现行级锁定的一种机制。当执行包含`FOR UPDATE`子句的`SELECT`语句时,Oracle会在所选择的行上放置排他锁(exclusive lock),即X锁,这种锁允许持有者读写数据,但阻止其他事务读写...
FOR UPDATE`: 对查询结果进行行级锁定,直到事务提交。 - `UPDATE`: 更新数据。 - `COMMIT`: 提交事务,解锁被锁定的行。 - `ROLLBACK`: 回滚事务,释放锁定。 2. **行级锁定与表级锁定**: - **行级锁定(Row...
FOR UPDATE`锁定的行,那么它将等待锁被释放,而`SELECT ... FOR UPDATE`的事务在等待`UPDATE`事务完成,从而形成死锁。 在提供的示例中,通过设置不同的`IsSuccess`值,展示了如何通过索引锁定导致死锁。当`...
FOR UPDATE`语句就是一种行级锁的用法,用于在更新数据前锁定选定的行,防止其他事务在此期间对这些行进行修改。当在查询条件中明确指定了主键,并且查询能够匹配到具体行时,InnoDB会实施行锁。例如: ```sql ...
如果不使用事务和`FOR UPDATE`,可能存在如下风险:在`SELECT`之后到`UPDATE`之前,其他事务可能已经将库存减少到0,但我们的事务仍然错误地更新了数量。为了解决这个问题,可以使用如下事务: 1. `SET AUTOCOMMIT=...
MySQL中的行级锁定是数据库管理并发事务的一种策略,它允许多个事务同时访问同一表的不同行,从而提高了系统并发性能。行级锁定主要分为两种类型:共享锁(Shared Locks)和排他锁(Exclusive Locks)。 共享锁,...
**保证线程安全的新方法:For Update** For Update是一种行级锁,它允许当前事务在查询并锁定数据行后,其他事务只能读取,而不能进行更新操作,直到当前事务提交或回滚。这种方式避免了并发事务间的冲突,确保了...
1. 行级锁:Oracle主要使用行级锁定来最小化锁定范围,提高并发性能。行级锁分为共享锁(S锁)和独占锁(X锁)。共享锁允许其他事务读取行,但阻止写入;独占锁则阻止其他事务读取或写入。 2. 表级锁:在特定情况下...
要解决这种冲突,我们可以使用 Oracle 的并发控制机制,例如使用 SELECT FOR UPDATE 语句来锁定记录,或者使用乐观锁机制来解决冲突。我们也可以使用 Oracle 的事务隔离级别来控制事务之间的交互。 在实际应用中,...
5. **锁竞争**:SQLite采用行级锁定,但在某些情况下仍可能出现锁竞争。当多用户同时更新同一数据时,会引发等待和锁冲突。合理规划并发访问,或者在设计数据库时考虑并发控制,有助于减轻锁竞争。 6. **查询优化**...
为了防止这种情况,我们可以使用InnoDB的行级锁定机制。 InnoDB支持两种锁:读共享锁(Read Shared Lock)和写独占锁(Write Exclusive Lock)。读共享锁允许其他事务读取数据,但不允许修改;写独占锁则阻止其他...
- `SELECT...FOR UPDATE`语句允许用户锁定多条记录进行更新,并且只有发起该查询的用户可以编辑这些记录,直至事务提交或回滚。 2. **表级锁**(Table-Level Locks) - **定义**:锁定整个表,限制其他用户对该表...
同时,SELECT...FOR UPDATE语句会为选定的行施加排他锁,使得只有发起查询的事务可以修改这些行,其他事务则被阻止进行修改,但仍然可以读取。 SELECT...FOR UPDATE语句的使用具有一定的灵活性。例如,你可以通过OF...
Oracle数据库在处理并发操作时,行级锁定机制起到了至关重要的作用,特别是在涉及多表更新的场景下。本文主要探讨了Oracle游标中的多表UPDATE行锁及其解决方案。 Oracle的锁定机制主要包括共享封锁、独占封锁和共享...
SELECT * FROM table_name WHERE condition FOR UPDATE; ``` - **表级锁定**: ```sql LOCK TABLE table_name IN EXCLUSIVE MODE; ``` #### 三、实用查询SQL语句 下面是一些常用的Oracle查询SQL语句,可以...
- **读的不可重复性**:SELECT FOR UPDATE语句用于锁定预期要修改的记录,防止其他事务在同一时间进行修改,常用于读-修改-写操作。 - **锁的相互作用**:不同类型的锁有不同的兼容性,例如,更新操作会加RX锁和X锁...
SELECT * FROM TEST WHERE ID = 10 FOR UPDATE NOWAIT; ``` 则会话A将立即获得锁定,否则将报错ORA-00054,表明没有立即获得锁定。 #### 六、更新锁定 假设会话A已经锁定了ID为10的记录,此时如果会话B尝试执行...