Hibernate实现悲观锁和乐观锁代码介绍
四种隔离机制不要忘记:(1,2,4,8)
1.read-uncommitted:能够去读那些没有提交的数据(允许脏读的存在)
2.read-committed:不会出现脏读,因为只有另一个事务提交才会读取来结果,但仍然会出现不可重复读和幻读现象。
4.repeatableread:MySQL默认。可重复读,读数据读出来之后给它加把锁,其他人先别更新,等我用完了你再更新。你的事务没完,其他事务就不可能改这条记录。
8.serializable:序列化,最高级别。一个一个来,不去并发。效率最低。
hibernate的隔离机制
i.hibernate.connection.isolation=2
ii.用悲观锁解决:repeatableread的问题(依赖于数据库的锁)
a)LockMode.None无锁的机制,Transaction结束时,切换到此模式
b)LockMode.read在查询的时候hibernate会自动获取锁
c)LockMode.writeinsertupdatehibernate会自动获取锁
d)以上3中锁的模式,是hibernate内部使用的
e)LockMode.UPGRADE_NOWAITORACLE支持的锁的方式
例子:
Account.java:
packagecom.bjsxt.hibernate;
importjavax.persistence.Entity;
importjavax.persistence.GeneratedValue;
importjavax.persistence.Id;
@Entity
publicclassAccount{
privateintid;
privateintbalance;//BigDecimal
@Id
@GeneratedValue
publicintgetId(){
returnid;
}
publicvoidsetId(intid){
this.id=id;
}
publicintgetBalance(){
returnbalance;
}
publicvoidsetBalance(intbalance){
this.balance=balance;
}
}
hibernate.cfg.xml中配置:
测试:
@Test
publicvoidtestSave(){
Sessionsession=sf.openSession();
session.beginTransaction();
Accounta=newAccount();
a.setBalance(100);
session.save(a);
session.getTransaction().commit();
session.close();
}
@Test
publicvoidtestOperation1(){
Sessionsession=sf.openSession();
session.beginTransaction();
Accounta=(Account)session.load(Account.class,1);
intbalance=a.getBalance();
//dosomecaculations
balance=balance-10;
//在保存时很有可能会把在同一时期修改的给覆盖掉
//这个时候上一把"锁"就可以避免这个问题
a.setBalance(balance);
session.getTransaction().commit();
session.close();
}
//下面这个就是对上面那个例子做的修改
@Test
publicvoidtestPessimisticLock(){
Sessionsession=sf.openSession();
session.beginTransaction();
//给它加把锁,加锁的机制上面已经提到了
Accounta=(Account)session.load(Account.class,1,LockMode.UPGRADE);
intbalance=a.getBalance();
//dosomecaculation
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:
packagecom.bjsxt.hibernate;
importjavax.persistence.Entity;
importjavax.persistence.GeneratedValue;
importjavax.persistence.Id;
importjavax.persistence.Version;
@Entity
publicclassAccount{
privateintid;
privateintbalance;
privateintversion;
@Version//加了这个注解就说明这个是专门用来做版本标注的
publicintgetVersion(){
returnversion;
}
publicvoidsetVersion(intversion){
this.version=version;
}
@Id
@GeneratedValue
publicintgetId(){
returnid;
}
publicvoidsetId(intid){
this.id=id;
}
publicintgetBalance(){
returnbalance;
}
publicvoidsetBalance(intbalance){
this.balance=balance;
}
}
测试:
@Test
publicvoidtestSave(){
Sessionsession=sf.openSession();
session.beginTransaction();
Accounta=newAccount();
a.setBalance(100);
session.save(a);
session.getTransaction().commit();
session.close();
}
@Test
publicvoidtestOptimisticLock(){
Sessionsession=sf.openSession();
Sessionsession2=sf.openSession();
session.beginTransaction();
Accounta1=(Account)session.load(Account.class,1);
session2.beginTransaction();
Accounta2=(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();
}
悲观乐观的区别:悲观锁认为一定会受到影响,我加锁谁也别想动。
乐观锁,没出事就好,出了事我再想办法解决。
总结
以上就是本文关于Hibernate实现悲观锁和乐观锁代码介绍的全部内容,希望对大家学习hibernate有所帮助。有什么问题可以随时留言,小编会及时回复大家。感谢大家对本站的支持。