mysqlsqlselectforupdate_数据库中SelectForupdate语句的解
析
——————————— Oracle —————————————————–
Oracle 的for update⾏锁
键字: oracle 的for update⾏锁
SELECT…FOR UPDATE 语句的语法如下:
SELECT … FOR UPDATE [OF column_list][WAIT n|NOWAIT][SKIP LOCKED];
其中:
OF ⼦句⽤于指定即将更新的列,即锁定⾏上的特定列。
WAIT ⼦句指定等待其他⽤户释放锁的秒数,防⽌⽆限期的等待。
“使⽤FOR UPDATE WAIT”⼦句的优点如下:
1防⽌⽆限期地等待被锁定的⾏;
2允许应⽤程序中对锁的等待时间进⾏更多的控制。
3对于交互式应⽤程序⾮常有⽤,因为这些⽤户不能等待不确定
4 若使⽤了skip locked,则可以越过锁定的⾏,不会报告由wait n 引发的‘资源忙’异常报告
⽰例1:
create table t(a varchar2(20),b varchar2(20));
insert into t values(‘1’,’1’);
insert into t values(‘2’,’2’);
insert into t values(‘3’,’3’);
insert into t values(‘4’,’4’);
现在执⾏如下操作:
在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秒后,报 资源忙的异常。
sql中update什么意思如果我们执⾏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中指定了需修改的列,则只有与这些列相关的表的⾏才会被锁定。
实例2
elect * from t for update 会等待⾏锁释放之后,返回查询结果。
select * from t for update nowait 不等待⾏锁释放,提⽰锁冲突,不返回结果
select * from t for update wait 5 等待5秒,若⾏锁仍未释放,则提⽰锁冲突,不返回结果
select * from t for update skip locked 查询返回查询结果,但忽略有⾏锁的记录
——————————— MySQL —————————————————–
MySQL中select * for update锁表的问题
页级:引擎 BDB。
表级:引擎 MyISAM , 理解为锁住整个表,可以同时读,写不⾏
⾏级:引擎 INNODB , 单独的⼀⾏记录加锁
表级,直接锁定整张表,在你锁定期间,其它进程⽆法对该表进⾏写操作。如果你是写锁,则其它进程则读也不允许
⾏级,,仅对指定的记录进⾏加锁,这样其它进程还是可以对同⼀个表中的其它记录进⾏操作。
页级,表级锁速度快,但冲突多,⾏级冲突少,但速度慢。所以取了折衷的页级,⼀次锁定相邻的⼀组记录。
MySQL 5.1⽀持对MyISAM和MEMORY表进⾏表级锁定,对BDB表进⾏页级锁定,对InnoDB表进⾏⾏级锁定。
对WRITE,MySQL使⽤的表锁定⽅法原理如下:
如果在表上没有锁,在它上⾯放⼀个写锁。
否则,把锁定请求放在写锁定队列中。
对READ,MySQL使⽤的锁定⽅法原理如下:
如果在表上没有写锁定,把⼀个读锁定放在它上⾯
否则,把锁请求放在读锁定队列中。
InnoDB使⽤⾏锁定,BDB使⽤页锁定。对于这两种存储引擎,都可能存在死锁。这是因为,在SQL语句处理期间,InnoDB⾃动获得⾏锁定和BDB获得页锁定,⽽不是在事务启动时获得。
MySQL中select * for update锁表的问题
由于InnoDB预设是Row-Level Lock,所以只有「明确」的指定主键,MySQL才会执⾏Row lock (只锁住被选取的资料例) ,否则MySQL将会执⾏Table Lock (将整个资料表单给锁住)。
举个例⼦:
假设有个表单products ,⾥⾯有id跟name⼆个栏位,id是主键。
例1: (明确指定主键,并且有此笔资料,row lock)
SELECT * FROM products WHERE id=’3’ FOR UPDATE;
SELECT * FROM products WHERE id=’3’ and type=1 FOR UPDATE;
例2: (明确指定主键,若查⽆此笔资料,⽆lock)
SELECT * FROM products WHERE id=’-1’ FOR UPDATE;
例2: (⽆主键,table lock)
SELECT * FROM products WHERE name=’Mouse’ FOR UPDATE;
例3: (主键不明确,table lock)
SELECT * FROM products WHERE id<>’3’ FOR UPDATE;
例4: (主键不明确,table lock)
SELECT * FROM products WHERE id LIKE ‘3’ FOR UPDATE;
注1: FOR UPDATE仅适⽤于InnoDB,且必须在交易区块(BEGIN/COMMIT)中才能⽣效。
注2: 要测试锁定的状况,可以利⽤MySQL的Command Mode ,开⼆个视窗来做测试。
在MySql 5.0中测试确实是这样的
另外:MyAsim 只⽀持表级锁,InnerDB⽀持⾏级锁
添加了(⾏级锁/表级锁)锁的数据不能被其它事务再锁定,也不被其它事务修改(修改、删除)
是表级锁时,不管是否查询到记录,都会锁定表
关于Oracle中for update的补充说明:
分成两类:加锁范围⼦句和加锁⾏为⼦句
加锁范围⼦句:
在select…for update之后,可以使⽤of⼦句选择对select的特定数据表进⾏加锁操作。默认情况下,不使⽤of⼦句表⽰在select所有的数据表中加锁
加锁⾏为⼦句:
当我们进⾏for update的操作时,与普通select存在很⼤不同。⼀般select是不需要考虑数据是否被锁定,最多根据多版本⼀致读的特性读取之前的版本。加⼊for update之后,Oracle就要求启动⼀个新事务,尝试对数据进⾏加锁。如果当前已经被加锁,默认的⾏为必然是block等待。使⽤nowait⼦句的作⽤就是避免进⾏等待,当发现请求加锁资源被锁定未释放的时候,直接报错返回。
在⽇常中,我们对for update的使⽤还是⽐较普遍的,特别是在如pl/sql developer中⼿⼯修改数据。此时只是觉得⽅便,⽽对for
update真正的含义缺乏理解。
For update是Oracle提供的⼿⼯提⾼锁级别和范围的特例语句。Oracle的锁机制是⽬前各类型数据库
锁机制中⽐较优秀的。所以,Oracle 认为⼀般不需要⽤户和应⽤直接进⾏锁的控制和提升。甚⾄认为死锁这类锁相关问题的出现场景,⼤都与⼿⼯提升锁有关。所以,Oracle并不推荐使⽤for update作为⽇常开发使⽤。⽽且,在平时开发和运维中,使⽤了for update却忘记提交,会引起很多锁表故障。
那么,什么时候需要使⽤for update?就是那些需要业务层⾯数据独占时,可以考虑使⽤for update。场景上,⽐如⽕车票订票,在屏幕上显⽰邮票,⽽真正进⾏出票时,需要重新确定⼀下这个数据没有被其他客户端修改。所以,在这个确认过程中,可以使⽤for update。这是统⼀的解决⽅案⽅案问题,需要前期有所准备。
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论