select for update与select for nowait

Select For Update行级锁定
OracleSelect For Update语句可以实现在读取数据后马上锁定相关资源,防止被其他session修改数据的目的。也就是我们常常谈到的“悲观锁定”(现实应用开发中,使用悲观锁定的情况少之又少,也许是因为乐观锁定的实现更加灵活和便捷的缘故)。

for update 和 for update nowait的区别是,别的事务要对这个表进行写操作时,是等待一段时间还是马上就被数据库系统拒绝而返回
这个小文儿做一个小小的实验,来看看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表示,我等你三秒的时间,如果三秒过后还无法锁定资源,就报错
在 PostgreSQL 中,`SELECT ... FOR UPDATE` 是一种用于在事务中锁定查询结果集中行的机制,确保其他事务无法修改这些行,直到当前事务完成。这种机制通常用于需要防止并发修改的场景,例如在金融交易、库存管理等系统中。 ### 用途 1. **行级锁定**:`SELECT ... FOR UPDATE` 会对查询结果集中的行加上排他锁,这意味着其他事务不能对这些行进行更新或删除操作,直到当前事务提交或回滚。这有助于防止数据竞争不一致的问题[^2]。 2. **并发控制**:通过锁定特定的行,`SELECT ... FOR UPDATE` 可以确保在事务处理过程中,数据不会被其他事务修改,从而保证数据的一致性完整性。 3. **避免死锁**:在某些情况下,使用 `SELECT ... FOR UPDATE` 可以帮助避免死锁。例如,当多个事务需要更新相同的行时,通过在事务开始时锁定这些行,可以确保事务按照一定的顺序执行,减少死锁的可能性[^4]。 ### 使用方法 1. **基本语法**:`SELECT ... FOR UPDATE` 的基本语法如下: ```sql SELECT * FROM table_name WHERE condition FOR UPDATE; ``` 其中 `table_name` 是要查询的表名,`condition` 是用于筛选行的条件。 2. **NOWAIT 选项**:如果希望在无法立即获取锁时立即返回错误而不是等待,可以使用 `NOWAIT` 选项。例如: ```sql SELECT * FROM table_name WHERE condition FOR UPDATE NOWAIT; ``` 如果其他事务已经锁定了所需的行,此查询将立即返回错误,而不是等待锁释放[^1]。 3. **SKIP LOCKED 选项**:如果希望跳过已经被其他事务锁定的行,可以使用 `SKIP LOCKED` 选项。例如: ```sql SELECT * FROM table_name WHERE condition FOR UPDATE SKIP LOCKED; ``` 这在处理队列或任务分配时非常有用,因为它允许跳过已经被其他事务处理的行。 4. **事务中使用**:`SELECT ... FOR UPDATE` 通常在事务中使用,以确保锁在整个事务期间保持有效。例如: ```sql BEGIN; SELECT * FROM table_name WHERE condition FOR UPDATE; -- 执行其他操作,例如 UPDATE 或 DELETE COMMIT; ``` ### 注意事项 - **死锁风险**:虽然 `SELECT ... FOR UPDATE` 可以帮助避免某些类型的死锁,但如果多个事务以不同的顺序锁定相同的资源,仍然可能导致死锁。因此,在设计应用程序时,应尽量确保事务以一致的顺序访问资源[^4]。 - **性能影响**:使用 `SELECT ... FOR UPDATE` 会增加数据库的锁竞争,可能会对性能产生影响。因此,应仅在必要时使用,并尽量减少锁定的行数锁定的时间。 ### 示例 假设有一个表 `number_of_form`,其中包含 `year`、`month` `number` 字段。在事务中使用 `SELECT ... FOR UPDATE` 来锁定特定行并更新其值: ```sql BEGIN; SELECT * FROM number_of_form WHERE year = '24' AND month = '02' FOR UPDATE; UPDATE number_of_form SET number = 3 WHERE uuid = 'your_uuid'; COMMIT; ``` 在这个例子中,`SELECT ... FOR UPDATE` 会锁定符合条件的行,确保在事务期间其他事务无法修改这些行,直到事务提交[^3]。 ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值