一、乐观锁介绍

乐观锁( Optimistic Locking ) 相对悲观锁而言,乐观锁假设认为数据一般情况下不会造成冲突,所以在数据进行提交更新的时候,才会正式对数据的冲突与否进行检,乐观锁适用于多读的应用类型,这样可以提高吞吐量,像数据库如果提供类似于write_condition机制的其实都是提供的乐观锁。类似SVN

悲观锁假定其他用户企图访问或者改变你正在访问、更改的对象的概率是很高的,因此在悲观锁的环境中,在你开始改变此对象之前就将该对象锁住,并且直到你提交了所作的更改之后才释放锁。

二、实现方式

1.使用数据版本(Version)记录机制实现,这是乐观锁最常用的一种实现方式。何谓数据版本?即为数据增加一个版本标识,一般是通过为数据库表增加一个数字类型的 “version” 字段来实现。当读取数据时,将version字段的值一同读出,数据每更新一次,对此version值加一。当我们提交更新的时候,判断数据库表对应记录的当前版本信息与第一次取出来的version值进行比对,如果数据库表当前版本号与第一次取出来的version值相等,则予以更新,否则认为是过期数据

2.乐观锁定的第二种实现方式和第一种差不多,同样是在需要乐观锁控制的table中增加一个字段,名称无所谓,字段类型使用时间戳(timestamp), 和上面的version类似,也是在更新提交的时候检查当前数据库中数据的时间戳和自己更新前取到的时间戳进行对比,如果一致则OK,否则就是版本冲突

三、乐观锁悲观锁区别

悲观的缺陷是不论是页锁还是行锁,加锁的时间可能会很长,这样可能会长时间的限制其他用户的访问,也就是说悲观锁的并发访问性不好。

乐观锁则认为其他用户企图改变你正在更改的对象的概率是很小的,因此乐观锁直到你准备提交所作的更改时才将对象锁住,当你读取以及改变该对象时并不加锁。可见乐观锁加锁的时间要比悲观锁短,乐观锁可以用较大的锁粒度获得较好的并发访问性能。

比如:如果第二个用户恰好在第一个用户提交更改之前读取了该对象,那么当他完成了自己的更改进行提交时,数据库就会发现该对象已经变化了,这样,第二个用户不得不重新读取该对象并作出更改。在乐观锁环境中,会增加并发用户读取对象的次数。

版本控制系统

如果数据是可变的,并且无法隔离呢?这种情况下最常用的两种控制就是乐观并发控制和悲观并发控制。

假设小张和小李想要同时修改同一个文件。如果使用乐观锁,俩人都能打开文件进行修改,如果小张先提交了内容,没有问题,他所做的改变会保存到服务器上。但小李提交时就会遇到麻烦,版本控制服务器会检测出两种修改的冲突,小李的提交会被具体,并由小李决定该如何处理这种情况(对于绝大部分版本控制软件来说,会读取并标识出小张做的改变,然后由小李决定是否合并)。

如果使用的是悲观锁,小张先检出(check out)文件,那么小李就无法再次检出同一文件,直到小张提交了他的改变

使用建议

将乐观锁想成一种检测冲突的手段,而悲观锁是一种避免冲突的手段(严格来说,乐观锁其实不能称之为“锁”,但是这个名字已经流传开了,那就继续使用吧)  ,乐观锁可以提高并发访问的效率,但是如果出现了冲突只能向上抛出,然后重来一遍

悲观锁可以避免冲突的发生,但是会降低效率,选择使用那一种锁取决于访问频率和一旦产生冲突的严重性

如果系统被并发访问的概率很低,或者冲突发生后的后果不太严重(所谓后果应该指被检测到冲突的提交会失败,必须重来一次),可以使用乐观锁,否则使用悲观锁

乐观锁的局限是只能在提交数据时才发现业务事务将要失败,而且在某些情况下,发现失败太迟的代价会很大。一个方法是使用悲观锁,它可以尽早地发现错误,但理难以编程实现,而且会降低系统的灵活性

四、MVCC中的实现方式

MySQL InnoDB存储引擎,实现的是基于多版本的并发控制协议——MVCC (Multi-Version Concurrency Control) (注:与MVCC相对的,是基于锁的并发控制,Lock-Based Concurrency Control)。MVCC最大的好处,相信也是耳熟能详:读不加锁,读写不冲突。在读多写少的OLTP应用中,读写不冲突是非常重要的,极大的增加了系统的并发性能,这也是为什么现阶段,几乎所有的RDBMS,都支持了MVCC

在InnoDB中,会在每行数据后添加两个额外的隐藏的值来实现MVCC,这两个值一个记录这行数据何时被创建,另外一个记录这行数据何时过期(或者被删除)。 在实际操作中,存储的并不是时间,而是事务的版本号,每开启一个新事务,事务的版本号就会递增。 在可重读Repeatable reads事务隔离级别下:

SELECT时,读取创建版本号<=当前事务版本号,删除版本号为空或>当前事务版本号。

INSERT时,保存当前事务版本号为行的创建版本号

DELETE时,保存当前事务版本号为行的删除版本号

UPDATE时,插入一条新纪录,保存当前事务版本号为行创建版本号,同时保存当前事务版本号到原来删除的行

通过MVCC,虽然每行记录都需要额外的存储空间,更多的行检查工作以及一些额外的维护工作,但可以减少锁的使用,大多数读操作都不用加锁,读数据操作很简单,性能很好,并且也能保证只会读取到符合标准的行,也只锁住必要行

在MVCC并发控制中,读操作可以分成两类:快照读 (snapshot read)与当前读 (current read)。快照读,读取的是记录的可见版本 (有可能是历史版本),不用加锁。当前读,读取的是记录的最新版本,并且,当前读返回的记录,都会加上锁,保证其他事务不会再并发修改这条记录。

在一个支持MVCC并发控制的系统中,哪些读操作是快照读?哪些操作又是当前读呢?以MySQL InnoDB为例:

快照读:简单的select操作,属于快照读,不加锁。(当然,也有例外,下面会分析)

select * from table where ?;

当前读:特殊的读操作,插入/更新/删除操作,属于当前读,需要加锁。

select * from table where ? lock in share mode;

select * from table where ? for update;

insert into table values (…);

update table set ? where ?;

delete from table where ?;

所有以上的语句,都属于当前读,读取记录的最新版本。并且,读取之后,还需要保证其他并发事务不能修改当前记录,对读取记录加锁。其中,除了第一条语句,对读取记录加S锁 (共享锁)外,其他的操作,都加的是X锁 (排它锁)。

mysql insert 乐观锁_【mysql】关于乐观锁相关推荐

  1. mysql 事务排他锁_[数据库事务与锁]详解六: MySQL中的共享锁与排他锁

    注明: 本文转载自http://www.hollischuang.com/archives/923 在MySQL中的行级锁,表级锁,页级锁中介绍过,行级锁是Mysql中锁定粒度最细的一种锁,行级锁能大 ...

  2. mysql和oracle的锁_关于数据库行锁与表锁的认识

    MySQL MySQL(InnoDB存储引擎)默认是自动提交事务的,所以这个测试,需要先将MySQL的autocommit设置为0,关闭自动提交,需要自己手动提交事务 -- 关闭自动提交 set au ...

  3. mysql insert 几分钟_我们可以在MySQL中应用INSERT语句时向VARCHAR日期时间记录添加分钟吗?...

    是的,我们可以在将值插入表中时增加分钟数.让我们首先创建一个表.在这里,我们有一列包含VARCHAR记录,其中mysql> create table DemoTable2026 -> ( ...

  4. mysql运维技巧_​mysql初级运维使用技巧

    整理了一下,工作中用到的最高的关于mysql的一些命令和使用技巧,分享给刚接触mysql的小伙伴么. 1mysql最基础 1.1mysql安装 建议新人安装mysql直接使用yum安装即可,大牛们已经 ...

  5. python如何实现人工智能应用锁_如何清除应用锁的数据库

    {"moduleinfo":{"card_count":[{"count_phone":1,"count":1}],&q ...

  6. 关抢占 自旋锁_关于Redis分布式锁这一篇应该是讲的最好的了,先收藏起来再看!...

    作者:Nan,气冲天. 原文:https://blog.csdn.net/qq_44209336 前言 在Java并发编程中,我们通常使用到synchronized .Lock这两个线程锁,Java中 ...

  7. zookeeper 分布式锁_关于redis分布式锁,zookeeper分布式锁原理的一些学习与思考

    编辑:业余草来源:https://www.xttblog.com/?p=4946 首先分布式锁和我们平常讲到的锁原理基本一样,目的就是确保,在多个线程并发时,只有一个线程在同一刻操作这个业务或者说方法 ...

  8. 关抢占 自旋锁_也说自旋锁

    前言 随着SMP处理器核越来越多 自旋锁是一种简单的轻量级的锁机制,理论上来说自旋锁可以小到一位,该位表示锁的状态,获取锁的线程尝试使用原子指令比较并交换该位,当锁不可用时反复自旋.自旋锁忙等待的机制 ...

  9. java 自旋锁与互斥锁_如何理解自旋锁和互斥锁?

    1.Python多线程run方法的中使用while循环时,如果在循环体没有使用停止程序机制,会一直运行下去.因此楼主如果想让编码方式得当,可以使用信号量或者其他变量机制通知循环体停止,或者判断队列是否 ...

  10. mysql insert 语句优化_分享insert into语句优化的小技巧

    MYSQL批量插入数据库实现语句性能分析 假定我们的表结构如下 代码如下CREATE TABLE example ( example_id INT NOT NULL, name VARCHAR( 50 ...

最新文章

  1. 电脑卡,eclipse Android stadio 卡,什么都卡解决方法
  2. docker 查看已安装容器_docker中的容器安装PHP扩展件
  3. vi插入模式下的backspace键和方向键“不正常”使用解决方法
  4. Angular的built-in指令
  5. oracle捕捉所有异常,如何捕获和处理特定的Oracle异常?
  6. java.lang.relect.Array 类
  7. 251f与ips屏显示器对比_8百左右预算,2020年PS平面设计/摄影后期显示器推荐/选购指南(全高清+高色域屏)...
  8. 使用UML工具分析类图与类的关系-bouml(java和C++)
  9. mysql 外键约束条件_MySQL-条件外键约束-问答-阿里云开发者社区-阿里云
  10. NDSS 2021 论文泛读
  11. oppo锁屏断网设置在哪里呀_oppo锁屏时钟怎么改格式?锁屏时钟位置在哪里设置调整...
  12. 麦咖啡的设置,很长,如果你想百毒不侵的话。。
  13. 设计c语言程序,输出形状为直角三角形的九九乘法表,c语言题库(全国c语言二级考试题库)...
  14. 提取网页内容-Python
  15. Java Promblem/Demand And Solution
  16. win10系统 DNS服务器,Win10系统DNS服务器无响应
  17. スーパーフィルター プライバシーポリシー
  18. Unity3D游戏开发初探—3.初步了解U3D物理引擎
  19. javascript百炼成仙 第一章 掌握JavaScript基础1.7 对象数据类型
  20. 有关颜色敏感度测试的软件是啥,色彩敏感度测试:你是色盲吗?

热门文章

  1. tf.constant_initializer
  2. C语言程序教程第一章答案,C语言教程课后习题答案
  3. k8s selector_k8s之Label与Selector
  4. 应用rs-485总线智能仪表实现计算机远程数据采集与监控,基于RS-485总线选矿厂电气控制系统的设计与实现本科毕业论文.doc...
  5. 肥仔学习日记----Docker Compose
  6. 不锈钢侧冲孔发光字制作过程中需留神的细节问题
  7. 什么是C103M日内阴线多于阳线选股指标?
  8. 【说啥都队-喻诗媛个人总结】
  9. 计算机领域常用单词(程序员常用单词)
  10. 将mnist数据集转换为对应的数字图片