Hibernate实现悲观锁和乐观锁代码介绍
作者:光仔December 发布时间:2022-04-25 09:43:45
四种隔离机制不要忘记:(1,2,4,8)
1.read-uncommitted:能够去读那些没有提交的数据(允许脏读的存在)
2.read-committed:不会出现脏读,因为只有另一个事务提交才会读取来结果,但仍然会出现不可重复读和幻读现象。
4.repeatable read: MySQL 默认。可重复读,读数据读出来之后给它加把锁,其他人先别更新,等我用完了你再更新。你的事务没完,其他事务就不可能改这条记录。
8.serializable:序列化,最高级别。一个一个来,不去并发。效率最低。
hibernate的隔离机制
i.hibernate.connection.isolation=2
ii.用悲观锁解决:repeatable read的问题(依赖于数据库的锁)
a)LockMode.None 无锁的机制,Transaction结束时,切换到此模式
b)LockMode.read 在查询的时候 hibernate会自动获取锁
c)LockMode.write insert update hibernate会自动获取锁
d)以上3中锁的模式,是hibernate内部使用的
e)LockMode.UPGRADE_NOWAIT ORACLE支持的锁的方式
例子:
Account.java:
package com.bjsxt.hibernate;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
@Entity
public class Account {
private int id;
private int balance; //BigDecimal
@Id
@GeneratedValue
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public int getBalance() {
return balance;
}
public void setBalance(int balance) {
this.balance = balance;
}
}
hibernate.cfg.xml中配置:
<mapping class="com.bjsxt.hibernate.Account"/>
测试:
@Test
public void testSave() {
Session session = sf.openSession();
session.beginTransaction();
Account a = new Account();
a.setBalance(100);
session.save(a);
session.getTransaction().commit();
session.close();
}
@Test
public void testOperation1() {
Session session = sf.openSession();
session.beginTransaction();
Account a = (Account)session.load(Account.class, 1);
int balance = a.getBalance();
//do some caculations
balance = balance - 10;
//在保存时很有可能会把在同一时期修改的给覆盖掉
//这个时候上一把"锁"就可以避免这个问题
a.setBalance(balance);
session.getTransaction().commit();
session.close();
}
//下面这个就是对上面那个例子做的修改
@Test
public void testPessimisticLock() {
Session session = sf.openSession();
session.beginTransaction();
//给它加把锁,加锁的机制上面已经提到了
Account a = (Account)session.load(Account.class, 1, LockMode.UPGRADE);
int balance = a.getBalance();
//do some caculation
balance = balance - 10;
a.setBalance(balance);
session.getTransaction().commit();
session.close();
}
这是依赖于数据库的锁的,也就是给数据库一个指令,要求数据库帮忙加锁。
——————————————————————————————————————
iii.Hibernate(JPA)乐观锁定(ReadCommitted)
这不是依赖数据库加锁的,是在程序中加锁的。
举个例子:一个数据需要隔离机制(不能重复读),这个时候在更新的字段上加"版本号"(version字段),一旦有人给它update一下,这个值就加1(version+1)。
那么这种机制是如何产生隔离能力的呢?
原因是事务A读取字段的同时,事务B紧接着也读取这个字段,而且改了它,此时version变成1了。这个时候事务A就会检查字段是否被改变了,如果被改变它也做相应的改变,没有改变就不改。
乐观锁的实现:(@Version)
Account.java:
package com.bjsxt.hibernate;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Version;
@Entity
public class Account {
private int id;
private int balance;
private int version;
@Version//加了这个注解就说明这个是专门用来做版本标注的
public int getVersion() {
return version;
}
public void setVersion(int version) {
this.version = version;
}
@Id
@GeneratedValue
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public int getBalance() {
return balance;
}
public void setBalance(int balance) {
this.balance = balance;
}
}
测试:
@Test
public void testSave() {
Session session = sf.openSession();
session.beginTransaction();
Account a = new Account();
a.setBalance(100);
session.save(a);
session.getTransaction().commit();
session.close();
}
@Test
public void testOptimisticLock() {
Session session = sf.openSession();
Session session2 = sf.openSession();
session.beginTransaction();
Account a1 = (Account) session.load(Account.class, 1);
session2.beginTransaction();
Account a2 = (Account) session2.load(Account.class, 1);
a1.setBalance(900);
a2.setBalance(1100);
//第一个session一旦提交,version就会+1
session.getTransaction().commit();
System.out.println(a1.getVersion());
//第二个session提交的时候,一看version不一样就会报错
//出了错误做个记录,下次再提交(也可以用其他方法)
session2.getTransaction().commit();
System.out.println(a2.getVersion());
session.close();
session2.close();
}
悲观乐观的区别:悲观锁认为一定会受到影响,我加锁谁也别想动。
乐观锁,没出事就好,出了事我再想办法解决。
来源:http://blog.csdn.net/acmman/article/details/44176281


猜你喜欢
- 本文实例讲述了Android编程使用Fragment界面向下跳转并一级级返回的实现方法。分享给大家供大家参考,具体如下:1.首先贴上项目结构
- 并发与并行:并行: 指两个或多个事件在同一时刻发生 ( 同时发生 ) 。并发: 指两个或多个事件在同一个时间段内发生。多线程使用场景:1.
- 本文实例为大家分享了java http token的具体代码,供大家参考,具体内容如下package com.monitoring.comm
- 一、前言今天我们来说一说 Spring Bean 的生命周期,小伙伴们应该在面试中经常遇到,这是正常现象。因为 Spring Bean 的生
- 实现比较两个List之间的差异,包括获取两List的差集,交集,并集(不去重&去重)的API解法和优化解法的解决方案。求差集/**
- Feign导入依赖为unknow的情况网上很多人在使用的feign时在pom.xml中的依赖为:<!-- SpringCloud 整合
- 这篇文章主要介绍了Java类加载器ClassLoader用法解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值
- 把C#编译成DLL或者Axtive控件,再由C调用!比如使用C++调用C#的DLL。SwfDotNet是.net下输出flash的类库。Sw
- 本文实例为大家分享了SpringBoot实现分页功能的具体代码,供大家参考,具体内容如下新建demo\src\main\java\com\e
- 1.概述在本快速教程中,我们将学习如何设置Spring Security LDAP。在我们开始之前,了解一下LDAP是什么? - 它代表轻量
- 背景Arthas是阿里巴巴开源的应用诊断利器,提供了profiler命令,可以生成热点火焰图。通过采样录制调用链路来做性能分析,极大提升了线
- 伤害数字显示HUD游戏中收到伤害掉血,会有飘动的伤害数值;可以使用OnGUI中GUI.Label来实现;可自定义字体,颜色,大小等;如果需要
- 最近在通讯录新建联系人=中,一进入一个页面, EditText默认就会自动获取焦点,很是郁闷, 如何让EditText不自动获取焦点?那么如
- 一般而言,一个项目部署的由:拉取代码->构建->测试->打包->部署等过程组成,如果我们经常需要部署项目,特别是在微
- 一、前言如何通过Java发送HTTP请求,通俗点讲,如何通过Java(模拟浏览器)发送HTTP请求。Java有原生的API可用于发送HTTP
- Java环境部署下载所需软件和依赖安装 jdk路径可选别的盘。但是指向时得注意我自己时装在 F 盘的,在f盘里新建文件夹 Java,Java
- Object 类位于 java.lang 包中,是所有 Java 类的祖先,Java 中的每个类都由它扩展而来。定义Java类时如果没有显示
- Runtime.getRuntime().exec 路径包含空格1. 现象java代码通过Runtime.getRuntime().exec
- 图片处理类:package com.longfei.admin.imageloder_text;import android.app.App
- 业务场景近年来B2C、O2O等商业概念的提出和移动端的发展,使得分布式系统流行了起来。分布式系统相对于单系统,解决了流量大、系统高可用和高容