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. Java控制语句——switch语句

    上述if语句的等值判断,可以用switch来代替. 注意每个case后面一般要添加break,表示当前这个case执行完了:防止出现case穿透,即继续执行case,直到遇到break才跳出. 下面例 ...

  2. Java final,static 关键字

    final关键字: 这是无法改变的”或者“终态的”含义,它可以修饰非抽象类.非抽象类成员方法和变量. final类不能被继承,没有子类,final类中的方法默认是final的.final方法不能被子类 ...

  3. WPF 应用程序使用 Multilingual App Toolkit

    应用程序支持多语言,使用 Multilingual App Toolkit是一个不错的解决方案. Multilingual App Toolkit下载地址: https://visualstudiog ...

  4. isKindOfClass和isMemberOfClass

    https://github.com/ming1016/study/wiki/Objc-Runtime 先看看isKindOfClass和isMemberOfClass在Object.mm中的实现 - ...

  5. 获取git的最后一次提交的commit id

    git log --pretty=format:"%h" | head -1  | awk '{print $1}' 可以放到xcode  build setting  post ...

  6. thttpd增加gzip压缩响应报文体功能,以减少传输数据量

    thttpd thttpd是一个非常小巧的轻量级web server,它非常非常简单,仅仅提供了HTTP/1.1和简单的CGI支持,在其官方网站上有一个与其他web server(如Apache, Z ...

  7. c++ unique_lock lock_guard

    unique_lock template <class Mutex> class unique_lock; Unique lock A unique lock is an object t ...

  8. Leetcode: Guess Number Higher or Lower

    We are playing the Guess Game. The game is as follows: I pick a number from 1 to n. You have to gues ...

  9. Ubuntu 16.04 LTS Final Beta

    期待已久的Ubuntu  LTS 版本开放了公测版本 Ubuntu 16.04 (Xenial Xerus) Daily Build(http://cdimage.ubuntu.com/daily-l ...

  10. java中时间的比较

    进入要比较从库中取出的时间,期初使用比较date.getTime()的值,但是当时间的年月日都相同时,时分秒较早的getTime()值比时分秒较晚的getTime()的值要大,至今笔者还不知这是为什么 ...