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. HTTP深入浅出 http请求

    HTTP(HyperText Transfer Protocol)是一套计算机通过网络进行通信的规则.计算机专家设计出HTTP,使HTTP客户(如Web浏览器)能够从HTTP服务器(Web服务器)请求 ...

  2. sql拼接字符串和转换类型

    select top 10 a.ID as a_ID,a.Name as a_Name,c.* from (select * from DC_Trees where Pid=187 or ID=187 ...

  3. 无线AP_H3C WA2620i-AGN配置

    设置Console口登录AP设备的用户进行密码认证: <Sysname> system-view //进入系统视图 [WA2620i-AGN]user-interface console ...

  4. category应用(计算nssting的数量)

    // //  main.m //  03-分类应用 // //  Created by apple on 14-3-18. //  Copyright (c) 2014年 apple. All rig ...

  5. cocos2dx 3.x(加载cocostudio进度条)

    // // MyLoagingScene.hpp // My // // Created by work on 16/10/13. // // #ifndef MyLoagingScene_hpp # ...

  6. Python生成8位随机密码

    #!/usr/bin/env python # -*- coding: utf- -*- import random import string #第一种方法 seed = "1234567 ...

  7. Dive into python 实例学python (2) —— 自省,apihelper

    apihelper.py def info(object, spacing=10, collapse=1): """Print methods and doc strin ...

  8. c# Task编程一个task抛出异常后怎么取消其他线程

    从MSDN的Forum上看到别人提供的解决方案,感觉还是比较靠谱,所以就保存下来. CancellationTokenSource cts = new CancellationTokenSource( ...

  9. 与PostgreSQL相关的工具

    Pentaho Data Integration(kettle):一个优秀的抽取.转换.加载(Extract Transform and Load,ETL)工具 Pentaho  Report Ser ...

  10. Leetcode: Trapping Rain Water II

    Given an m x n matrix of positive integers representing the height of each unit cell in a 2D elevati ...