Hibernate实现悲观锁和乐观锁。

1,悲观锁

用例代码如下:

  • 数据库DDL语句:
  • hibernate.cfg.xml
  • java类

以上代码(除下面的main之外)同乐观锁。

main

 package a3_Version;
import org.hibernate.LockOptions;
import org.hibernate.Session;
import daoUtil.HibernateUtil; public class Test_pessiLock { public static void main(String[] args) {
Session session = HibernateUtil.getSession(); try {
Cat cat = (Cat)session.get(Cat.class, "8a6cc5a34c54de57014c54de588e0000", LockOptions.UPGRADE); System.out.println("这行设置断点,到数据库");
System.out.println("使用SQL:select * from CAT t WHERE T.ID='"+cat.getId()+"' FOR UPDATE");
System.out.println("验证CAT表,ID='"+cat.getId()+"'的行数据是否被锁住了。");
} catch (RuntimeException e) {
throw e;
} finally {
session.close();
}
}
}

2,乐观锁

JPA通过@Version添加对表数据的乐观锁定的支持

根据EJB3规范,version列可以是numeric类型(推荐方式)也可以是timestamp类型. Hibernate支持任何自定义类型,只要该类型实现了UserVersionType.

用例代码如下:

  • 数据库DDL语句:
 create table CAT
(
id VARCHAR2(32 CHAR) not null,
create_time TIMESTAMP(6),
update_time TIMESTAMP(6),
cat_name VARCHAR2(255 CHAR),
version NUMBER(10) not null
)
  • hibernate.cfg.xml
 <?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE hibernate-configuration
PUBLIC "-//Hibernate/Hibernate Configuration DTD//EN"
"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<!-- 数据库驱动配置 -->
<property name="dialect">org.hibernate.dialect.Oracle10gDialect</property>
<property name="connection.driver_class">oracle.jdbc.OracleDriver</property>
<property name="connection.url">jdbc:oracle:thin:@127.0.0.1:1521:orcl</property>
<property name="connection.username">wxuatuser</property>
<property name="connection.password">xlh</property>
<property name="show_sql">true</property>
<!-- 自动执行DDL属性是update,不是true -->
<property name="hbm2ddl.auto">update</property>
<!-- hibernate实体类 --> <mapping class="a3_Version.Cat"/> </session-factory>
</hibernate-configuration>
  • java类

实体类 - 基类

 package model;
import java.io.Serializable;
import java.util.Date;
import javax.persistence.Column;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.MappedSuperclass;
import org.hibernate.annotations.GenericGenerator;
/**
* 实体类 - 基类
*/
@MappedSuperclass
public class BaseEntity implements Serializable { private static final long serialVersionUID = -6718838800112233445L; private String id;// ID
private Date create_time;// 创建日期
private Date update_time;// 修改日期
@Id
@Column(length = 32, nullable = true)
@GeneratedValue(generator = "uuid")
@GenericGenerator(name = "uuid", strategy = "uuid")
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
@Column(updatable = false)
public Date getCreate_time() {
return create_time;
}
public void setCreate_time(Date create_time) {
this.create_time = create_time;
}
public Date getUpdate_time() {
return update_time;
}
public void setUpdate_time(Date update_time) {
this.update_time = update_time;
}
@Override
public int hashCode() {
return id == null ? System.identityHashCode(this) : id.hashCode();
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass().getPackage() != obj.getClass().getPackage()) {
return false;
}
final BaseEntity other = (BaseEntity) obj;
if (id == null) {
if (other.getId() != null) {
return false;
}
} else if (!id.equals(other.getId())) {
return false;
}
return true;
}
}

实体类

 package a3_Version;
import javax.persistence.Entity;
import javax.persistence.Version;
import model.BaseEntity;
import org.hibernate.annotations.DynamicInsert;
import org.hibernate.annotations.DynamicUpdate; @Entity
@DynamicInsert
@DynamicUpdate
public class Cat extends BaseEntity{
/**
* 实体类
*/
private static final long serialVersionUID = -2776330321385582872L; private String cat_name; private int version;
@Version
public int getVersion() {
return version;
} public void setVersion(int version) {
this.version = version;
} public String getCat_name() {
return cat_name;
} public void setCat_name(String cat_name) {
this.cat_name = cat_name;
}
}

Dao

 package daoUtil;
import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;
import org.hibernate.service.ServiceRegistry;
import org.hibernate.service.ServiceRegistryBuilder; public class HibernateUtil { private static final SessionFactory sessionFactory; static {
try {
Configuration cfg = new Configuration().configure();
ServiceRegistry serviceRegistry = new ServiceRegistryBuilder()
.applySettings(cfg.getProperties()).buildServiceRegistry();
sessionFactory = cfg.buildSessionFactory(serviceRegistry);
} catch (Throwable ex) {
throw new ExceptionInInitializerError(ex);
}
} public static Session getSession() throws HibernateException {
return sessionFactory.openSession();
} public static Object save(Object obj){
Session session = HibernateUtil.getSession();
Transaction tx = null;
try {
tx = session.beginTransaction();
session.save(obj);
tx.commit();
} catch (RuntimeException e) {
if (tx != null) {
tx.rollback();
}
throw e;
} finally {
session.close();
}
return obj;
} public static void delete(Class<?> clazz,String id){
Session session = HibernateUtil.getSession();
Transaction tx = null;
try {
tx = session.beginTransaction();
Object obj = session.get(clazz,id);
session.delete(obj);
tx.commit();
} catch (RuntimeException e) {
if (tx != null) {
tx.rollback();
}
throw e;
} finally {
session.close();
}
}
}

main

 package a3_Version;
import java.util.ArrayList;
import java.util.Iterator;
import org.hibernate.Session;
import org.hibernate.StaleObjectStateException;
import org.hibernate.Transaction;
import a3_Version.Cat;
import daoUtil.HibernateUtil; public class Test_optiLock extends Thread { private String transactionType;
private Log log;
private String id; public Test_optiLock(String transactionType, Log log,String id) {
this.transactionType = transactionType;
this.log = log;
this.id = id;
} public Test_optiLock() {} public void run() {
try {
if (transactionType.equals("modify"))
modify(id);
else
update(id);
} catch (Exception e) {
e.printStackTrace();
}
} public void modify(String id) throws Exception {
Session session = HibernateUtil.getSession();
Transaction tx = null;
try {
tx = session.beginTransaction();
log.write("modify():开始事务");
Thread.sleep(500); Cat cat = (Cat) session.get(Cat.class, id); log.write("modify():查询到cat_name为:" + cat.getCat_name());
Thread.sleep(500); cat.setCat_name(cat.getCat_name()+"modify");
log.write("modify():把cat_name改为:" + cat.getCat_name()); tx.commit();
log.write("modify():提交事务");
Thread.sleep(500);
} catch (StaleObjectStateException e) {
if (tx != null) {
tx.rollback();
}
e.printStackTrace();
System.out.println("cat_name已被其他事务修改,本事务被撤销,请重新开始modify事务");
log.write("modify():cat_name已被其他事务修改,本事务被撤销");
} catch (RuntimeException e) {
if (tx != null) {
tx.rollback();
}
throw e;
} finally {
session.close();
}
} public void update(String id) throws Exception {
Session session = HibernateUtil.getSession();
Transaction tx = null;
try {
tx = session.beginTransaction();
log.write("update():开始事务");
Thread.sleep(500); Cat cat = (Cat) session.get(Cat.class, id); log.write("update():查询到cat_name为:" + cat.getCat_name());
Thread.sleep(500); cat.setCat_name(cat.getCat_name()+"update");
log.write("update():把cat_name改为:" + cat.getCat_name()); tx.commit();
log.write("update():提交事务");
Thread.sleep(500);
} catch (StaleObjectStateException e) {
if (tx != null) {
tx.rollback();
}
e.printStackTrace();
System.out.println("cat_name已被其他事务修改,本事务被撤销,请重新开始update事务");
log.write("update():cat_name已被其他事务修改,本事务被撤销");
} catch (RuntimeException e) {
if (tx != null) {
tx.rollback();
}
throw e;
} finally {
session.close();
}
} public static void main(String args[]) throws Exception {
Cat cat = new Cat();
cat.setCat_name("test3@optiLock");
HibernateUtil.save(cat); Log log = new Log();
String id = cat.getId();
Thread modifyThread = new Test_optiLock("modify", log ,id);
Thread updateThread = new Test_optiLock("update", log ,id); modifyThread.start();
updateThread.start(); while (modifyThread.isAlive() || updateThread.isAlive()) {
Thread.sleep(100);
}
log.print();
}
} class Log {
private ArrayList<String> logs = new ArrayList<String>(); synchronized void write(String text) {
logs.add(text);
} public void print() {
for (Iterator<String> it = logs.iterator(); it.hasNext();) {
System.out.println(it.next());
}
}
}

执行后控制台信息如下:

Hibernate: insert into Cat (cat_name, version, id) values (?, ?, ?)
Hibernate: select cat0_.id as id1_0_0_, cat0_.create_time as create_t2_0_0_, cat0_.update_time as update_t3_0_0_, cat0_.cat_name as cat_name4_0_0_, cat0_.version as version5_0_0_ from Cat cat0_ where cat0_.id=?
Hibernate: select cat0_.id as id1_0_0_, cat0_.create_time as create_t2_0_0_, cat0_.update_time as update_t3_0_0_, cat0_.cat_name as cat_name4_0_0_, cat0_.version as version5_0_0_ from Cat cat0_ where cat0_.id=?
Hibernate: update Cat set cat_name=?, version=? where id=? and version=?
Hibernate: update Cat set cat_name=?, version=? where id=? and version=?
org.hibernate.StaleObjectStateException: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect): [a3_Version.Cat#8a6cc5a34c6ea5f2014c6ea5f3740000]
at org.hibernate.persister.entity.AbstractEntityPersister.check(AbstractEntityPersister.java:2523)
at org.hibernate.persister.entity.AbstractEntityPersister.update(AbstractEntityPersister.java:3242)
at org.hibernate.persister.entity.AbstractEntityPersister.updateOrInsert(AbstractEntityPersister.java:3140)
at org.hibernate.persister.entity.AbstractEntityPersister.update(AbstractEntityPersister.java:3470)
at org.hibernate.action.internal.EntityUpdateAction.execute(EntityUpdateAction.java:140)
at org.hibernate.engine.spi.ActionQueue.execute(ActionQueue.java:393)
at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:385)
at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:302)
at org.hibernate.event.internal.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:339)
at org.hibernate.event.internal.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:52)
at org.hibernate.internal.SessionImpl.flush(SessionImpl.java:1240)
at org.hibernate.internal.SessionImpl.managedFlush(SessionImpl.java:404)
at org.hibernate.engine.transaction.internal.jdbc.JdbcTransaction.beforeTransactionCommit(JdbcTransaction.java:101)
at org.hibernate.engine.transaction.spi.AbstractTransactionImpl.commit(AbstractTransactionImpl.java:175)
at a3_Version.Test_optiLock.update(Test_optiLock.java:87)
at a3_Version.Test_optiLock.run(Test_optiLock.java:29)
cat_name已被其他事务修改,本事务被撤销,请重新开始update事务
modify():开始事务
update():开始事务
modify():查询到cat_name为:test3@optiLock
update():查询到cat_name为:test3@optiLock
modify():把cat_name改为:test3@optiLockmodify
update():把cat_name改为:test3@optiLockupdate
modify():提交事务
update():cat_name已被其他事务修改,本事务被撤销

  数据库层面,存入数据时,version是0,update后是1。

环境:JDK1.6,MAVEN

源码地址:http://files.cnblogs.com/files/xiluhua/hibernate%40Version.rar

Hibernate,JPA注解@Version的更多相关文章

  1. Java、Hibernate(JPA)注解大全

    1.@Entity(name=”EntityName”) 必须,name为可选,对应数据库中一的个表 2.@Table(name=””,catalog=””,schema=””) 可选,通常和@Ent ...

  2. hibernate jpa 注解 @Temporal(TemporalType.DATE) 格式化时间日期,页面直接得到格式化类型的值

    1.日期: @Temporal(TemporalType.DATE) @Column(name = "applyDate", nullable = false, length = ...

  3. 【hibernate/JPA】注解方式实现 复合主键【spring boot】

    1>hibernate/JPA实现复合主键的思路:是将所有的主键属性封装在一个主键类中,提供给需要复合主键的实体类使用. 2>主键类的几点要求: . 使用复合主键的实体类必须实现Seria ...

  4. hibernate自带的注解和jpa注解的冠希

    hibernate是实现了JPA规范,在我们使用hibernate框架的时候,我们引入了hibernate3或者4这个核心包.hibernate-jpa-2.0-api-1.0.0.Final.jar ...

  5. Hibernate 和 JPA 注解

    转载请注明:Hibernate 和 JPA 注解 | 言曌博客 1.@Entity(name="EntityName") 必须, name为可选,对应数据库中一的个表 2.@Tab ...

  6. Hibernate基于注解方式配置来实现实体和数据库之间存在某种映射关系

    实体和数据库之间存在某种映射关系,hibernate根据这种映射关系完成数据的存取.在程序中这种映射关系由映射文件(*.hbm.xml)或者java注解(@)定义. 本文以java注解的形式总结映射关 ...

  7. Hibernate+JPA (EntityMange讲解)

    近年来ORM(Object-Relational Mapping)对象关系映射,即实体对象和数据库表的映射)技术市场人声音鼎沸,异常热闹, Sun在充分吸收现有的优秀ORM框架设计思想的基础上,制定了 ...

  8. spring+hibernate+jpa+Druid的配置文件,spring整合Druid

    spring+hibernate+jpa+Druid的配置文件 spring+hibernate+jpa+Druid的完整配置 spring+hibernate+jpa+Druid的数据源配置 spr ...

  9. Hibernate+JPA

    参考链接:http://blog.163.com/hero_213/blog/static/398912142010312024809 近年来ORM(Object-Relational Mapping ...

随机推荐

  1. 不连数据库List分页

    package com.jpsycn.kfwggl.common.crawl; import java.util.ArrayList; import java.util.List; public cl ...

  2. sequelize翻译(1)

    第一次翻译(由mongoose转了mysql) v 3.0.0 1.Sequelize类 2.sequelize对象 3.sequelize.define()返回的表对象 4.表对象的方法 1.Seq ...

  3. Java Volatile关键字

    在当前的Java内存模型下,线程可以把变量保存在本地内存(比如机器的寄存器)中,而不是直接在主存中进行读写. 这就可能造成一个线程在主存中修改了一个变量的值,而另外一个线程还继续使用它在寄存器中的变量 ...

  4. [ArcEngine]IFeatureBuffer使用

    public static void LoadOnlyModeInsert(IFeatureClass featureClass, List < IGeometry > geometryL ...

  5. CSS浮动与清浮动

    浮动 ( float css属性) float : left right Elements are floated horizontally, this means that an element c ...

  6. cache与SDRAM

    hugohong hugohong 本版等级:   #2 得分:20回复于: 2009-04-19 21:51:03 牛人说的,拿出来分享一下:cache是高速缓冲, 解决高速cpu和相对低速sdra ...

  7. java 笔记(4) —— java I/O 流、字节流、字符流

    Java中使用流来处理程序的输入和输出操作,流是一个抽象的概念,封装了程序数据于输入输出设备交换的底层细节.JavaIO中又将流分为字节流和字符流,字节流主要用于处理诸如图像,音频视频等二进制格式数据 ...

  8. c语言的基本语法

    1. 二目运算符从右往左 优先级 运算符 名称或含义 使用形式 结合方向 说明 1 [] 数组下标 数组名[常量表达式] 左到右   () 圆括号 (表达式)/函数名(形参表)   . 成员选择(对象 ...

  9. DIY小能手|别买电动滑板车了,咱做一台吧

    !! http://www.shoudian.org/thread-316111-1-1.html http://www.jiequer.com/html/news/xinpin/2014/1218/ ...

  10. PHP isset()与empty()的使用区别详解

    通过对PHP语言的学习,应该知道它是基于函数的一款HTML脚本语言.庞大的函数库支持着PHP语言功能的实现.下面我们为大家介绍有关PHP函数isset()与empty()的相关用法.   PHP的is ...