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描述符指定。

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

  1. **Java有哪些悲观锁的实现_面试4连问:乐观锁与悲观锁的概念、实现方式、场景、优缺点?...

    推荐阅读: 数据库面试4连问:分库分表,中间件,优缺点,如何拆分? 终极手撕之架构大全:分布式+框架+微服务+性能优化,够不够? 消息队列面试,你能顶得住面试官这波10大连环炮的攻势吗? 01 乐观锁 ...

  2. spring mysql事物级别_mysql事务级别和spring中应用

    一.事务的基本要素(ACID) 1.原子性(Atomicity):事务开始后所有操作,要么全部做完,要么全部不做,不可能停滞在中间环节.事务执行过程中出错,会回滚到事务开始前的状态,所有的操作就像没有 ...

  3. 13.简述MYSQL的权限级别_MySQL权限级别

    MySQL权限级别 MySQL 中的权限分为五个级别,分别如下: 1.Global Level: Global Level 的权限控制又称为全局权限控制,所有权限信息都保存在mysql.user 表中 ...

  4. jpa mysql乐观锁_【快学springboot】8.JPA乐观锁OptimisticLocking

    介绍 当涉及到企业应用程序时,正确地管理对数据库的并发访问是至关重要的.为此,我们可以使用Java Persistence API提供的乐观锁定机制.它导致在同一时间对同一数据进行多次更新不会相互干扰 ...

  5. mysql级别_mysql事务级别

    一.隔离级别 隔离级别(Isolation Level) SQL标准定义了4类隔离级别,包括了一些具体规则,用来限定事务内外的哪些改变是可见的,哪些是不可见的.低级别的隔离级一般支持更高的并发处理,并 ...

  6. mysql插入2000万数据_Mysql千万级别数据批量插入,性能提高

    -----------------------------------------------------------方式1 ------------------------------------- ...

  7. mysql乐观锁与事务_Mysql中的读锁,写锁,乐观锁及事务隔离级别和并发问题

    mysql读锁,写锁,乐观锁 读锁,也叫共享锁(shared lock) SELECT * FROM table_name  WHERE ...  LOCK IN SHARE MODE 写锁,也叫排他 ...

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

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

  9. mysql悲观锁和乐观优缺点_乐观锁、悲观锁和MVCC各是什么?各自优缺点是什么?...

    在数据库的实际使用过程中,我们常常会遇到不希望数据被同时写或者读的情景,例如秒杀场景下,两个请求同时读到系统还有库存1个,然后又先后把库存更新为0,这时候就会出现超卖的情况,这时候货物的实际库存和我们 ...

  10. mysql数据锁的类型_MySQL数据库锁类型

    锁概念: 当高并发访问同一个资源时,可能会导致数据不一致,需要一种机制将用户访问数据的顺序进行规范化,以保证数据库数据的一致性.锁就是其中的一种机制. 一个栗子 :以买火车票为例,火车票可面向广大消费 ...

最新文章

  1. 使用 Sticky-Kit 实现基于 jQuery 的元素固定效果
  2. JQuery Ajax解读(3)
  3. WCF分布式开发步步为赢(15):错误契约(FaultContract)与异常处理(ExceptionHandle)
  4. c语言报错spawning 插1,C语言错误····error spawning c1.exe
  5. BigPipe 大的页面分割成一个一个管道
  6. 彻底理解SESSION
  7. Android Bitmap 开源图片框架分析(精华四)
  8. html标签%3cli%3e分成两列,使用html自制玫瑰
  9. C语言· 实现各进制间的相互转换
  10. Linux与网络服务(零)从零开始聊聊Linux相关概念(科普向)
  11. select下拉框option默认选中(php模板渲染)
  12. java调用录像_java调用摄像头拍照录像
  13. QGIS编译---QGIS3.10.6 + Qt5.11.2 + VS2015 ---32位版本
  14. 化繁为简,远光天擎助你一键云部署
  15. 烙铁使用注意事项及元器件件焊接要点
  16. tp6 gatewayWorker
  17. 最新版X-Helios、X-Medusa、X-Ladon、X-Argus逆向与风控分析
  18. 教你彻底卸载MySQL 并重装(保姆级教程 )
  19. LOGO设计辅助图形的人性化设计
  20. PMP考试章节口诀-关键词篇(1~7章)

热门文章

  1. Windows10:将cmd命令行添加到右键中的方法
  2. 一天不学习我浑sen难受(一)—一致性哈希/Hash环学习笔记
  3. 综述 | 基于特征的视觉同步定位和建图
  4. 小目标Trick | Detectron2、MMDetection、YOLOv5都通用的小目标检测解决方案
  5. window下安装scapy
  6. mysql alter 增加修改表结构及约束
  7. 洛谷 1776 宝物筛选 【多重背包+二进制拆分】
  8. 注册表的基本操作(.Net)
  9. char* char [] 区别[zz]
  10. Sql server 2000导入 Sql server 2005的数据