mysql存在则更新 并发_SQL Server与MySQL在“存在则更新,不存在则插入”并发处理上的一些差异。...

“存在则更新,不存在则插入的逻辑”并发情况下的处理

在sqlserver中:

在sqlserver中,是通过可序列化隔离级别+排它锁的方式来锁定一个范围来实现的

当前锁定一个不存在的记录的时候,sqlserver是通过范围锁来实现的,具体锁定的范围,表中已存在的数据和当前具体判断的Id有关

参考之前写的一篇文章:http://www.cnblogs.com/wy123/p/7501261.html

简单举个例子,如下表中的表中没有任何数据行,Id 字段是primary key

a468f8dbbf0044cbc5f1abd8be30984d.png

当前Session锁定一个不存在的记录

在另外一个Session中试图锁定相同的记录的时候被阻塞(go提交之后没有任何返回结果,实际上是Session被阻塞)

第一个Session开水器事务

1df1e3e64e00d6f3c71c02f98dabbc37.png

实际上当前Session锁定的范围是从表中的最小值(没有最小值就是无穷小)到无穷大的一个范围

也就是说说不但锁定了当前Session锁定的Id = 66的数据,甚至只66到正无穷大的数据也被锁定.

babf066df68490a3b441a47fefe9fc7e.png

以上也即就是sqlserver中范围锁的效果以及适应的场景,可能有其他中写的变种,比如with(serializable),或者with(holdlock),或者先更新再判断受影响行数啥的

本质上都是:序列化隔离级别+事务+排它锁,不但可以锁定已存在的记录行,也可以锁定不存在的记录行。

因此不必纠结各种写法的差异,本质都是一样的。

set transaction isolation level serializable;begin tran

if exists (select * from TestLockNotExistId with(xlock) where Id = 66)begin

--更新

update TestLockNotExistId set CreateDate = getdate()end

else

begin

--插入

insert TestLockNotExistId values (66,'xxx',getdate())end

commit

在MySQL中:

在MySQL中,是通过insert into values on duplicate key update语法实现的,

虽然MySQL中有类似于SQLServer中显式加锁的语法,也即select from where for update,原本以为可以使用 for update语法来照搬SQL Server的方式实现类似资源隔离

但是经过测试时候,mysql的for update方式显然是锁不住不存在的记录的

但是select from where for update只能锁定已存在的记录,而锁不住不存在的记录

以下测试,无法锁住不存在的记录

238733d9fc76004ccb794436b758bbe1.png

可以锁定已存在的记录

38e75a7e8678e79510e0df1dfcfb34d4.png

因此MySQL中的GAP锁,虽然表面含义也是区间锁(范围锁),与SQLServer中的范围锁,在细节上还是有一定的差异的。

MySQL在默认的Reapted Read隔离级别下,虽然通过GAP锁解决了幻读的问题,

但是这种锁仅仅是在读写之间阻塞(互斥)的,在读与读之间,即便是select显式加排它锁的方式,不同Session的同一个不存在Id的查询,也是不阻塞。

因此无法通过先判断是否存在,再决定是插入或者更新的方式来实现。

内容来源于网络如有侵权请私信删除

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值