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

标签:hibernate,悲观锁,乐观锁
0
投稿

猜你喜欢

  • 详解Java中Iterable与Iterator用法

    2022-05-14 04:25:30
  • Java 8 动态类型语言Lambda表达式实现原理解析

    2023-08-05 09:04:25
  • Java利用三目运算符比较三个数字的大小

    2023-04-18 01:20:19
  • Java发送报文与接收报文的实例代码

    2023-07-09 04:44:01
  • Java解析调用webservice服务的返回XML串详解

    2023-11-07 02:42:01
  • Java中List使用stream流转成map的几种方式详解

    2022-07-31 21:46:12
  • Seata AT模式如何实现行锁详解

    2022-11-18 23:43:34
  • Java线程创建的四种方式总结

    2023-10-29 19:36:03
  • JAVA SPI特性及简单应用代码实例

    2021-11-11 14:54:54
  • Java lombok中@Accessors注解三个属性的作用

    2022-04-20 14:32:27
  • Android+SQLite数据库实现的生词记事本功能实例

    2023-06-18 10:41:35
  • 通过Java连接SQL Server数据库的超详细操作流程

    2022-08-01 12:46:01
  • 关于使用Mybatisplus自带的selectById和insert方法时的一些问题

    2023-11-01 14:15:42
  • java实现截取PDF指定页并进行图片格式转换功能

    2023-08-24 02:58:56
  • 简单的java图片处理类(图片水印 图片缩放)

    2022-04-02 03:24:37
  • intellij idea中spring boot properties文件不能自动提示问题解决

    2021-09-24 09:53:46
  • 一文带你了解C#中的协变与逆变

    2022-08-06 22:31:21
  • android中使用SharedPreferences进行数据存储的操作方法

    2023-06-16 17:37:42
  • 布隆过滤器面试如何快速判断元素是否在集合里

    2022-10-17 15:55:19
  • 基于springboot搭建的web系统架构的方法步骤

    2023-11-21 13:33:51
  • asp之家 软件编程 m.aspxhome.com