2019独角兽企业重金招聘Python工程师标准>>>

1、什么是悲观锁,乐观锁

悲观锁大多数情况下依靠数据库的锁机制实现,以保证操作最大程度的独占性。但随之而来的就是数据库性能的大量开销,特别是对长事务而言,这样的开销往往无法承受。而乐观锁机制在一定程度上解决了这个问题。乐观锁,大多是基于数据版本( Version )记录机制实现。何谓数据版本?即为数据增加一个版本标识,在基于数据库表的版本解决方案中,一般是通过为数据库表增加一个 “version” 字段来实现。读取出数据时,将此版本号一同读出,之后更新时,对此版本号加一。此时,将提交数据的版本数据与数据库表对应记录的当前版本信息进行比对,如果提交的数据版本号大于数据库表当前版本号,则予以更新,否则认为是过期数据。

悲观锁:假定会发生并发冲突,屏蔽一切可能违反数据完整性的操作。[1]

乐观锁:假设不会发生并发冲突,只在提交操作时检查是否违反数据完整性。[1]乐观锁不能解决脏读的问题。

乐观锁应用

1.     使用自增长的整数表示数据版本号。更新时检查版本号是否一致,比如数据库中数据版本为6,更新提交时version=6+1,使用该version值(=7)与数据库version+1(=7)作比较,如果相等,则可以更新,如果不等则有可能其他程序已更新该记录,所以返回错误。

2.     使用时间戳来实现.

注:对于以上两种方式,Hibernate自带实现方式:在使用乐观锁的字段前加annotation: @Version, Hibernate在更新时自动校验该字段。

悲观锁应用

需要使用数据库的锁机制,比如SQL SERVER 的TABLOCKX(排它表锁) 此选项被选中时,SQL  Server  将在整个表上置排它锁直至该命令或事务结束。这将防止其他进程读取或修改表中的数据。

数据库锁机制:
       共享锁:由读表操作加上的锁,加锁后其他用户只能获取该表或行的共享锁,不能获取排它锁,也就是说只能读不能写。

   排它锁:由写表操作加上的锁,加锁后其他用户不能获取该表或行的任何锁。

锁的范围:

   行锁: 对某行记录加上锁

   表锁: 对整个表加上锁

这样组合起来就有,行级共享锁,表级共享锁,行级排他锁,表级排他锁。

结论

在实际生产环境里边,如果并发量不大且不允许脏读,可以使用悲观锁解决并发问题;但如果系统的并发非常大的话,悲观锁定会带来非常大的性能问题,所以我们就要选择乐观锁定的方法.

2、事务并发会产生什么问题

1)第一类丢失更新:在没有事务隔离的情况下,两个事务都同时更新一行数据,但是第二个事务却中途失败退出, 导致对数据的两个修改都失效了。

例如:

张三的工资为5000,事务A中获取工资为5000,事务B获取工资为5000,汇入100,并提交数据库,工资变为5100,

随后事务A发生异常,回滚了,恢复张三的工资为5000,这样就导致事务B的更新丢失了。

2)脏读:脏读就是指当一个事务正在访问数据,并且对数据进行了修改,而这种修改还没有提交到数据库中,这时,另外一个事务也访问这个数据,然后使用了这个数据。
例如:
  张三的工资为5000,事务A中把他的工资改为8000,但事务A尚未提交。
  与此同时,
  事务B正在读取张三的工资,读取到张三的工资为8000。
  随后,
  事务A发生异常,而回滚了事务。张三的工资又回滚为5000。
  最后,
  事务B读取到的张三工资为8000的数据即为脏数据,事务B做了一次脏读。

3)不可重复读:是指在一个事务内,多次读同一数据。在这个事务还没有结束时,另外一个事务也访问该同一数据。那么,在第一个事务中的两次读数据之间,由于第二个事务的修改,那么第一个事务两次读到的的数据可能是不一样的。这样就发生了在一个事务内两次读到的数据是不一样的,因此称为是不可重复读。
例如:
  在事务A中,读取到张三的工资为5000,操作没有完成,事务还没提交。
  与此同时,
  事务B把张三的工资改为8000,并提交了事务。
  随后,
  在事务A中,再次读取张三的工资,此时工资变为8000。在一个事务中前后两次读取的结果并不致,导致了不可重复读。

4)第二类丢失更新:不可重复读的特例。有两个并发事务同时读取同一行数据,然后其中一个对它进行修改提交,而另一个也进行了修改提交。这就会造成第一次写操作失效。

例如:

在事务A中,读取到张三的存款为5000,操作没有完成,事务还没提交。
  与此同时,
  事务B,存储1000,把张三的存款改为6000,并提交了事务。
  随后,
  在事务A中,存储500,把张三的存款改为5500,并提交了事务,这样事务A的更新覆盖了事务B的更新。

5)幻读:是指当事务不是独立执行时发生的一种现象,例如第一个事务对一个表中的数据进行了修改,这种修改涉及到表中的全部数据行。同时,第二个事务也修改这个表中的数据,这种修改是向表中插入一行新数据。那么,以后就会发生操作第一个事务的用户发现表中还有没有修改的数据行,就好象发生了幻觉一样。
例如:
  目前工资为5000的员工有10人,事务A读取所有工资为5000的人数为10人。
  此时,
  事务B插入一条工资也为5000的记录。
  这是,事务A再次读取工资为5000的员工,记录为11人。此时产生了幻读。

提醒:
不可重复读的重点是修改:
同样的条件,你读取过的数据,再次读取出来发现值不一样了
幻读的重点在于新增或者删除:
同样的条件,第 1 次和第 2 次读出来的记录数不一样

3、事务隔离级别,解决什么并发问题

(1)READ_UNCOMMITTED
  这是事务最低的隔离级别,它充许别外一个事务可以看到这个事务未提交的数据。
  会出现脏读、不可重复读、幻读 (隔离级别最低,并发性能高)。
(2)READ_COMMITTED
  保证一个事务修改的数据提交后才能被另外一个事务读取。另外一个事务不能读取该事务未提交的数据。
  可以避免脏读,但会出现不可重复读、幻读问题(锁定正在读取的行)。
(3)REPEATABLE_READ
  可以防止脏读、不可重复读,但会出幻读(锁定所读取的所有行)。
(4)SERIALIZABLE
  这是花费最高代价但是最可靠的事务隔离级别,事务被处理为顺序执行。
  保证所有的情况不会发生(锁表)。

详情见下表:

提醒:

Mysql默认的事务隔离级别为repeatable_read

4、悲观锁和乐观锁与数据库隔离级别的关系

关系总结,事务隔离级别是并发控制的整体解决方案,其实际上是综合利用各种类型的锁和行版本控制,来解决并发问题。锁是数据库并发控制的内部机制,是基础。对用户来说,只有当事务隔离级别无法解决一些并发问题和需求时,才有必要在语句中手动设置锁。

5、悲观锁和乐观锁的使用

1)悲观锁:

要使用悲观锁,我们必须关闭mysql数据库的自动提交属性,因为MySQL默认使用autocommit模式,也就是说,当你执行一个更新操作后,MySQL会立刻将结果进行提交。

使用mybatis或者jdbc api实现时:

sql语句:select status from t_goods where id=1 for update;,update t_goods set status=2;,这时id为1的记录会被锁住

使用hibernate实现时,

Criteria.setLockMode 
Query.setLockMode 
Session.lock 
注意,只有在查询开始之前(也就是Hiberate 生成SQL 之前)设定加锁,才会 真正通过数据库的锁机制进行加锁处理,否则,数据已经通过不包含for update 子句的Select SQL加载进来,所谓数据库加锁也就无从谈起。

2)乐观锁:

乐观锁是系统层面的实现,推荐的实现方案是表中新增一个version字段,然后基于version字段的更新来判断事务是否有效。

使用mybatis或者jdbc api实现时:

select (status,status,version) from t_goods where id=#{id}
update t_goods 
set status=2,version=version+1
where id=#{id} and version=#{version};

更新操作是基于version的,当事务A更新了记录之后,version字段会加1,事务B再根据之前的version去查找记录的时候,数据库没有相应的记录就会出现异常,这时系统捕捉异常进行处理,即可避免并发的问题。

使用hibernate实现时:

Hibernate中必须指定optimistic-lock属性对version描述符指定。

转载于:https://my.oschina.net/u/2277088/blog/1630187

mysql隔离级别与悲观锁、乐观锁相关推荐

  1. mysql 乐观锁 脏读_mysql 丢失更新1和2、脏读、不可重复读和幻读 事务隔离级别 悲观锁 乐观锁...

    事务是现代关系型数据库的核心之一.在多个事务并发操作数据库(多线程.网络并发等)的时候,如果没有有效的避免机制,就会出现以下几种问题: ( 第一类丢失更新 A事务撤销时,把已经提交的B事务的更新数据覆 ...

  2. MySql事务4种隔离级别以及悲观锁和乐观锁

    前言:在那鬼公司呆着发现自己居然把事务给搞明白了. 缘由:公司做的一个项目在进行首页内容显示的时候发现查询结果特别慢,有时候需要一到五分钟才能显示出结果.于是乎,我就顺着SQL语句查询慢的原因找了下去 ...

  3. mysql悲观群_谈谈mysql的悲观和乐观锁

    悲观锁与乐观锁是两种常见的资源并发锁设计思路,也是并发编程中一个非常基础的概念.之前有写过一篇文章关于并发的处理思路和解决方案,这里我单独将对这两种常见的锁机制在数据库数据上的实现进行比较系统的介绍一 ...

  4. MySQL - 行锁 表锁 乐观锁 悲观锁 读锁 写锁

    MySQL - 行锁 表锁 乐观锁 悲观锁 读锁 写锁 锁是在执行多线程时用于强行限制资源访问的同步机制,即用于在并发控制中保证对互斥要求的满足.在DBMS中,可以按照锁的粒度把数据库锁分为行级锁(I ...

  5. java 对变量加锁_Java最全锁剖析:独享锁/共享锁+公平锁/非公平锁+乐观锁/悲观锁...

    乐观锁 VS 悲观锁 乐观锁与悲观锁是一种广义上的概念,体现了看待线程同步的不同角度,在Java和数据库中都有此概念对应的实际应用. 1.乐观锁 顾名思义,就是很乐观,每次去拿数据的时候都认为别人不会 ...

  6. Java锁详解:“独享锁/共享锁+公平锁/非公平锁+乐观锁/悲观锁+线程锁”

    在Java并发场景中,会涉及到各种各样的锁如公平锁,乐观锁,悲观锁等等,这篇文章介绍各种锁的分类: 公平锁/非公平锁 可重入锁 独享锁/共享锁 乐观锁/悲观锁 分段锁 自旋锁 线程锁 乐观锁 VS 悲 ...

  7. innodb 悲观锁 乐观锁_mysql乐观锁、悲观锁、共享锁、排它锁、行锁、表锁

    mysql乐观锁.悲观锁.共享锁.排它锁.行锁.表锁 乐观锁 总是假设最好的情况,每次去拿数据的时候都认为别人不会修改,所以不会上锁,但是在更新的时候会判断一下在此期间别人有没有去更新这个数据,可以使 ...

  8. 最全Java锁详解:独享锁/共享锁+公平锁/非公平锁+乐观锁/悲观锁

    在Java并发场景中,会涉及到各种各样的锁,比如:高并发编程系列:4种常用Java线程锁的特点,性能比较.使用场景,这些锁有对应的种类:公平锁,乐观锁,悲观锁等等,这篇文章来详细介绍各种锁的分类: 公 ...

  9. 理解悲观锁乐观锁、同步锁、读锁、写锁

    ava 锁分类 Java 中的锁有很多,可以按照不同的功能.种类进行分类,下面是我对 Java 中一些常用锁的分类,包括一些基本的概述 从线程是否需要对资源加锁可以分为 悲观锁 和 乐观锁 从资源已被 ...

最新文章

  1. Eclipse中出现JS文件前有红叉的解决方法
  2. codeforces B. Fox and Cross 解题报告
  3. Java反编译器的剖析
  4. java int integer内存_java中一个integer对象的内存占用是多少?可以通过java方法输出吗?...
  5. 织梦dede 5.7系统基本参数无法修改保存,提示Token mismatch!
  6. FreeBSD与Linux的比较
  7. python从文件初始化失败_iOS 6:libpython2.7.a初始化导入错误
  8. (转)Android text文字阴影设置
  9. 98五笔86五笔及五笔字型口诀字根表
  10. UEFI原理与编程(七):包及.dsc、.dec、.fdf文件
  11. 一元线性回归(R语言)
  12. Android 图片加载框架Glide主流程源码分析
  13. python 生孩子朋友圈_新生儿出生朋友圈说说,生孩子报喜唯美句子
  14. 小程序调用服务器图片错误,微信小程序列表图片加载错误处理
  15. 微信小程序加载图片优化
  16. 怎么用u盘重装系统?石大师u盘重装win10系统步骤
  17. 2023年湖北一级技师二级技师报名时间、考试时间是什么时候?
  18. docker配置Java环境
  19. (原)详解生产线物流规划的原理及操作方式
  20. python3个引号啥意思_Python中单引号,双引号,3个单引号及3个双引号的区别

热门文章

  1. EasyX识别不到VC++6.0
  2. Redis五种数据结构详解
  3. 多层陶瓷电容器用处_陶瓷电容的作用及特点
  4. sql怎么把小数变百分比_云计算基本技能有哪些 怎么监控Linux系统内存
  5. Halcon初学者知识:用set_paint直观显示图像的属性
  6. c++ websocket客户端_你要的websocket都在这,收好不谢~~~
  7. @angular/core里的 NgZone -使得Angular不跟踪变化
  8. c++ 11新特性总结_JDK1.8新特性Stream和Collectors19个常用示例总结
  9. linux clock命令,Linux中clock命令起什么作用呢?
  10. 第七天2017/04/14(C++对C的扩充,C++与C的区别,C++的基础知识)