当前位置: 首页 > news >正文

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

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

在sqlserver中:

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

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

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

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

af25578ef88a3a1e8a14a407a4a0c5c9.png

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

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

第一个Session开水器事务

b4a0b119be1dc0f90759c5e14674fbc7.png

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

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

3e3c99277bb9c6be82055d0d2bc2e15d.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中,是通过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只能锁定已存在的记录,而锁不住不存在的记录

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

a421b550df53cb977c4bf70b602b9912.png

可以锁定已存在的记录

2ba6a7d4daf5508d51bc0c0f95f79bd2.png

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

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

但是这种锁仅仅是在读写之间阻塞(互斥)的,在读与读之间,即便是select显式加排它锁的方式,不同Session的同一个不存在Id的查询,也是不阻塞(MySQL的gap锁不阻塞,也就是说两个gap锁,锁定的范围完全一致的时候,如果这个范围内没有数据,则不会互相阻塞)。

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

20191213补充:

mysql中,对于不存再插入,存在则更新,从sql语句上是无法解决的,经测试,以下Version1和Version2两种写法,并发时均潜在死锁的问题

Version1

insert into t01 (parameter_key )

SELECT parameter_key

WHERE NOT EXISTS

(SELECT 1 FROM t01 AS t WHERE t.key = parameter_key);

Version2

insert into t01 (parameter_key )

SELECT parameter_key

ON DUPLICATE KEY UPDATE

lastupdate_date = now()

如下Version3的写法,会给出警告

Version3

insert IGNORE into t01 (parameter_key )

SELECT parameter_key

insert ignore与ON DUPLICATE KEY UPDATE是不兼容的,也就是说,MySQL想要达到“存在更新不存在插入的效果”,sql层面是无法解决的

纯sql层面,各种奇淫技巧根本无法解决死锁的问题,因此最终方案:

1,除非显式锁定表,执行插入或者更新语句,最后解锁

#cursor.execute('lock tables t01 WRITE,t01 AS t read;')

cursor.execute(sql_statment)

#cursor.execute('unlock tables;')

2,增加异常重试次数

相关文章:

  • MySQL时间加20天_mysql日期加一个天数获得新的日期
  • mysql创建子用户代码_mysql 创办用户
  • mysql 条件查询view_C#mysql数据库查询根据条件显示dataGridView
  • 引用类型如何避免数据结构的无穷嵌套问题_「Rust巅峰之作」- 从来没有谁能把数据类型讲的如此透彻...
  • 写个函数计算所有传入参数相乘的结果(参数数量不定)_Python 函数的封装
  • vue调用百度地图api_Vue Baidu Map 可能是 Vue 接入百度地图 API 的最佳组件了
  • mysql5.7执行计划 导出_Oracle执行计划和数据导出、MySQL入门
  • centos 7 yum卸载redis_不小心把Centos的yum给卸载了怎么办
  • mysql数据库uid是什么意思_mysql数据库权限及编码
  • mac os php mysql_教你如何在Mac OS系统搭建PHP环境及MySQL,原来这么简单
  • MySQL explain 例子_MySql]explain用法及实践
  • python中signature是什么意思_什么是Python中的異域函數簽名?
  • mysql 支持的逻辑匹配_Mariadb MySQL逻辑条件判断相关语句、函数使用举例介绍
  • mysql数据库备份还原表_MySQL数据库及表的备份与还原_MySQL
  • element ui 12 中进度条标签不能展示_vue中引入elementUI,关于修改默认样式的几点总结...
  • [rust! #004] [译] Rust 的内置 Traits, 使用场景, 方式, 和原因
  • 【comparator, comparable】小总结
  • 【React系列】如何构建React应用程序
  • 03Go 类型总结
  • Angular数据绑定机制
  • CentOS从零开始部署Nodejs项目
  • classpath对获取配置文件的影响
  • css选择器
  • Django 博客开发教程 8 - 博客文章详情页
  • github指令
  • Golang-长连接-状态推送
  • idea + plantuml 画流程图
  • Js基础——数据类型之Null和Undefined
  • Xmanager 远程桌面 CentOS 7
  • 电商搜索引擎的架构设计和性能优化
  • 模仿 Go Sort 排序接口实现的自定义排序
  • 字符串匹配基础上
  • 扩展资源服务器解决oauth2 性能瓶颈
  • ​如何在iOS手机上查看应用日志
  • #LLM入门|Prompt#1.7_文本拓展_Expanding
  • (70min)字节暑假实习二面(已挂)
  • (C语言)深入理解指针2之野指针与传值与传址与assert断言
  • (function(){})()的分步解析
  • (八)Docker网络跨主机通讯vxlan和vlan
  • (附源码)springboot 房产中介系统 毕业设计 312341
  • (附源码)springboot猪场管理系统 毕业设计 160901
  • (附源码)ssm基于web技术的医务志愿者管理系统 毕业设计 100910
  • (转)利用PHP的debug_backtrace函数,实现PHP文件权限管理、动态加载 【反射】...
  • .NET 程序如何获取图片的宽高(框架自带多种方法的不同性能)
  • .NET 反射的使用
  • .NET/C# 反射的的性能数据,以及高性能开发建议(反射获取 Attribute 和反射调用方法)
  • .NET/C# 利用 Walterlv.WeakEvents 高性能地定义和使用弱事件
  • .NET的数据绑定
  • @staticmethod和@classmethod的作用与区别
  • [ vulhub漏洞复现篇 ] Celery <4.0 Redis未授权访问+Pickle反序列化利用
  • [AMQP Connection 127.0.0.1:5672] An unexpected connection driver error occured
  • [APIO2012] 派遣 dispatching
  • [BeginCTF]真龙之力
  • [dart学习]第四篇:函数
  • [docker]docker网络-直接路由模式