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

乐观锁和悲观锁

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

乐观锁:

原理:
	1)通过在数据库表中添加一个版本号(version)字段来实现乐观锁。
	2)更新前先获取到该条数据的版本号(v1),然后在更新语句(更新数据&更新版本号)的where条件中添加 version=v1 条件,
		1>若满足version=v1条件(即:成功获取乐观锁),则成功更新数据且版本号+1;
		2>若不满足version=v1条件(即:获取乐观锁失败),说明该条数据被其它线程修改过了,则更新失败,回滚事务。
特点:
	1)不发生获取锁失败的情况下,开销比较小。
	2)若获取锁失败,则代码需要回滚,开销比较大。
	
应用:
	乐观锁适用于锁获取失败的概率比较小的场景,即:读取比较频繁、写入较少的场景。

缺点:
	只能保证本系统对数据(数据库表)的操作是安全的,外部系统对数据(数据库表)的操作是不可控的。
	解决办法:对外部系统设置权限,即外部系统只有普通查询的权限。

悲观锁:

原理:使用数据库提供的锁机制(select .. for update)。

注意:使用悲观锁前,必须先关闭MySQL的自动提交属性。

应用:
	写入比较频繁的场景。

我们应该尽量避免使用长事务:

1)在一个事务中执行批量操作(eg:循环插入数据、循环删除数据等)会导致该事务的执行时间变长。
2)长事务会导致数据库连接被长时间持有,如果该请求的并发量较高,则很可能出现连接池中的连接被用光的情况,从而导致其它的请求(因无法获取到数据库连接)一直处于等待状态,无法被响应。
3)我们应该将事务的范围控制在单个操作上。

Hibernate中的乐观锁和悲观锁:

概念:指数据库的隔离级别设为read committed时,为了解决不可重复读的问题而采用的两种办法:

1)设定hibernate的事务隔离级别(使用hibernate.connection.isolation配置:取值1、2、4、8)
	hibernate.connection.isolation = 2(如果不设,则默认依赖数据库本身的级别)
2)采用乐观锁和悲观锁解决不可重复读的问题
	1)悲观锁:使用另一种load方法:load(xx.class , id , LockMode.Upgrade),把读出来的数据加上一把锁,在事务结束前别人无法访问,需要借助数据库中的锁。
		注:LockMode.UPGRADE_NOWAIT是 ORACLE 支持的锁的方式
	2)乐观锁:在程序中添加一个version字段,用来检查是否被修改过。版本检查使用版本号或者时间戳来检测更新冲突(并且防止更新丢失)。
		在实体类中增加version属性(数据库也会对应生成该字段,初始值为0),并在其get方法前加@Version注解,则在操作过程中每更新一次该行数据则version值加1,即可在事务提交前判断该数据是否被其他事务修改过。

eg:
	悲观锁(PessimisticLock):

	public void testPessimisticLock() {
		Session session = sf.openSession();
		session.beginTransaction();
		
		// LockMode.UPGRADE 的意思就是:在读这条记录的时候,请数据库为我读的这条记录加把锁
		Account a = (Account)session.load(Account.class, 1L, LockMode.UPGRADE);
		int balance = a.getBalance();
		//do some caculation
		balance = balance - 10;
		a.setBalance(balance);
		
		session.getTransaction().commit();
		session.close();
	}

	控制台发出的SQL语句:select ... for update	
	分析:在select语句后加上了for update,说明这里在数据库中加了一把锁。

转载于:https://my.oschina.net/u/1399755/blog/1797008

相关文章:

  • Linux初始设置
  • PostgreSQL 11 preview - 分页内核层优化 - 索引扫描offset优化(使用vm文件skip heap scan)...
  • linux下jdb远程调试tomcat源码
  • PostgreSQL 11 preview - pgbench 支持大于1000链接(ppoll()代替select())
  • 数字操作符九度OJ 1019 简单计算器
  • NO1 ip-systemctl-fdisk
  • 执行对象cocos2d-x 2.x action动作整理集合
  • MySQL主从复制介绍
  • C# 使用GDI+绘制漂亮的ToolStrip和StatusStrip皮肤(转载)
  • Win32编程点滴3 - 简单ActiveX控件的使用
  • 禁止鼠标选中文字
  • HDU2553 N皇后问题
  • [转]给年轻工程师的十大忠告
  • Flutter 安装
  • CYQ.Data V5 批量插入与批量更新示例
  • [译]CSS 居中(Center)方法大合集
  • 2017前端实习生面试总结
  • java8 Stream Pipelines 浅析
  • javascript 哈希表
  • jQuery(一)
  • JS函数式编程 数组部分风格 ES6版
  • Laravel核心解读--Facades
  • Netty源码解析1-Buffer
  • nginx(二):进阶配置介绍--rewrite用法,压缩,https虚拟主机等
  • PermissionScope Swift4 兼容问题
  • PhantomJS 安装
  • python 学习笔记 - Queue Pipes,进程间通讯
  • spark本地环境的搭建到运行第一个spark程序
  • vue-cli在webpack的配置文件探究
  • Webpack 4 学习01(基础配置)
  • 第2章 网络文档
  • 区块链技术特点之去中心化特性
  • 让你的分享飞起来——极光推出社会化分享组件
  • 温故知新之javascript面向对象
  • 硬币翻转问题,区间操作
  • 用quicker-worker.js轻松跑一个大数据遍历
  • “十年磨一剑”--有赞的HBase平台实践和应用之路 ...
  • 【运维趟坑回忆录 开篇】初入初创, 一脸懵
  • Linux权限管理(week1_day5)--技术流ken
  • ​插件化DPI在商用WIFI中的价值
  • ​软考-高级-信息系统项目管理师教程 第四版【第23章-组织通用管理-思维导图】​
  • $redis-setphp_redis Set命令,php操作Redis Set函数介绍
  • (附源码)springboot猪场管理系统 毕业设计 160901
  • (十七)Flask之大型项目目录结构示例【二扣蓝图】
  • (算法)N皇后问题
  • (五)大数据实战——使用模板虚拟机实现hadoop集群虚拟机克隆及网络相关配置
  • (转)jQuery 基础
  • (转)创业家杂志:UCWEB天使第一步
  • .mat 文件的加载与创建 矩阵变图像? ∈ Matlab 使用笔记
  • .net CHARTING图表控件下载地址
  • .net core 6 redis操作类
  • .net core 6 集成和使用 mongodb
  • .Net core 6.0 升8.0
  • .NET Remoting Basic(10)-创建不同宿主的客户端与服务器端
  • .net 简单实现MD5