Hibernate,JPA注解@Version

 Hibernate实现悲观锁和乐观锁。

1,悲观锁

用例代码如下:

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

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

main

 1 package a3_Version;
 2 import org.hibernate.LockOptions;
 3 import org.hibernate.Session;
 4 import daoUtil.HibernateUtil;
 5 
 6 public class Test_pessiLock {
 7 
 8     public static void main(String[] args) {
 9         Session session = HibernateUtil.getSession();
10     
11         try {
12             Cat cat = (Cat)session.get(Cat.class, "8a6cc5a34c54de57014c54de588e0000", LockOptions.UPGRADE);
13             
14             System.out.println("这行设置断点,到数据库");
15             System.out.println("使用SQL:select * from CAT t WHERE T.ID='"+cat.getId()+"' FOR UPDATE");
16             System.out.println("验证CAT表,ID='"+cat.getId()+"'的行数据是否被锁住了。");
17         } catch (RuntimeException e) {
18             throw e;
19         } finally {
20             session.close();
21         }
22     }
23 }

2,乐观锁

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

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

用例代码如下:

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

实体类 - 基类 

 1 package model;
 2 import java.io.Serializable;
 3 import java.util.Date;
 4 import javax.persistence.Column;
 5 import javax.persistence.GeneratedValue;
 6 import javax.persistence.Id;
 7 import javax.persistence.MappedSuperclass;
 8 import org.hibernate.annotations.GenericGenerator;
 9 /**
10  * 实体类 - 基类
11  */
12 @MappedSuperclass
13 public class BaseEntity implements Serializable {
14 
15     private static final long serialVersionUID = -6718838800112233445L;
16 
17     private String id;// ID
18     private Date create_time;// 创建日期
19     private Date update_time;// 修改日期
20     @Id
21     @Column(length = 32, nullable = true)
22     @GeneratedValue(generator = "uuid")
23     @GenericGenerator(name = "uuid", strategy = "uuid")
24     public String getId() {
25         return id;
26     }
27     public void setId(String id) {
28         this.id = id;
29     }
30     @Column(updatable = false)
31     public Date getCreate_time() {
32         return create_time;
33     }
34     public void setCreate_time(Date create_time) {
35         this.create_time = create_time;
36     }
37     public Date getUpdate_time() {
38         return update_time;
39     }
40     public void setUpdate_time(Date update_time) {
41         this.update_time = update_time;
42     }
43     @Override
44     public int hashCode() {
45         return id == null ? System.identityHashCode(this) : id.hashCode();
46     }
47     @Override
48     public boolean equals(Object obj) {
49         if (this == obj) {
50             return true;
51         }
52         if (obj == null) {
53             return false;
54         }
55         if (getClass().getPackage() != obj.getClass().getPackage()) {
56             return false;
57         }
58         final BaseEntity other = (BaseEntity) obj;
59         if (id == null) {
60             if (other.getId() != null) {
61                 return false;
62             }
63         } else if (!id.equals(other.getId())) {
64             return false;
65         }
66         return true;
67     }
68 }

实体类

 1 package a3_Version;
 2 import javax.persistence.Entity;
 3 import javax.persistence.Version;
 4 import model.BaseEntity;
 5 import org.hibernate.annotations.DynamicInsert;
 6 import org.hibernate.annotations.DynamicUpdate;
 7 
 8 @Entity
 9 @DynamicInsert
10 @DynamicUpdate
11 public class Cat extends BaseEntity{
12     /**
13      * 实体类
14      */
15     private static final long serialVersionUID = -2776330321385582872L;
16     
17     private String cat_name;
18     
19     private int version;
20     @Version
21     public int getVersion() {
22         return version;
23     }
24 
25     public void setVersion(int version) {
26         this.version = version;
27     }
28     
29     public String getCat_name() {
30         return cat_name;
31     }
32 
33     public void setCat_name(String cat_name) {
34         this.cat_name = cat_name;
35     }
36 }

Dao

 1 package daoUtil;
 2 import org.hibernate.HibernateException;
 3 import org.hibernate.Session;
 4 import org.hibernate.SessionFactory;
 5 import org.hibernate.Transaction;
 6 import org.hibernate.cfg.Configuration;
 7 import org.hibernate.service.ServiceRegistry;
 8 import org.hibernate.service.ServiceRegistryBuilder;
 9 
10 public class HibernateUtil {
11 
12     private static final SessionFactory sessionFactory;
13 
14     static {
15         try {
16             Configuration cfg = new Configuration().configure();
17             ServiceRegistry serviceRegistry = new ServiceRegistryBuilder()
18                     .applySettings(cfg.getProperties()).buildServiceRegistry();
19             sessionFactory = cfg.buildSessionFactory(serviceRegistry);
20         } catch (Throwable ex) {
21             throw new ExceptionInInitializerError(ex);
22         }
23     }
24 
25     public static Session getSession() throws HibernateException {
26         return sessionFactory.openSession();
27     }
28 
29     public static Object save(Object obj){
30         Session session = HibernateUtil.getSession();
31         Transaction tx = null;
32         try {
33             tx = session.beginTransaction();
34             session.save(obj);
35             tx.commit();
36         } catch (RuntimeException e) {
37             if (tx != null) {
38                 tx.rollback();
39             }
40             throw e;
41         } finally {
42             session.close();
43         }
44         return obj;
45     }
46     
47     public static void delete(Class<?> clazz,String id){
48         Session session = HibernateUtil.getSession();
49         Transaction tx = null;
50         try {
51             tx = session.beginTransaction();
52             Object obj = session.get(clazz,id);
53             session.delete(obj);
54             tx.commit();
55         } catch (RuntimeException e) {
56             if (tx != null) {
57                 tx.rollback();
58             }
59             throw e;
60         } finally {
61             session.close();
62         }
63     }
64 }

main

  1 package a3_Version;
  2 import java.util.ArrayList;
  3 import java.util.Iterator;
  4 import org.hibernate.Session;
  5 import org.hibernate.StaleObjectStateException;
  6 import org.hibernate.Transaction;
  7 import a3_Version.Cat;
  8 import daoUtil.HibernateUtil;
  9 
 10 public class Test_optiLock extends Thread {
 11     
 12     private String transactionType;
 13     private Log log;
 14     private String id;
 15 
 16     public Test_optiLock(String transactionType, Log log,String id) {
 17         this.transactionType = transactionType;
 18         this.log = log;
 19         this.id = id;
 20     }
 21     
 22     public Test_optiLock() {}
 23     
 24     public void run() {
 25         try {
 26             if (transactionType.equals("modify"))
 27                 modify(id);
 28             else
 29                 update(id);
 30         } catch (Exception e) {
 31             e.printStackTrace();
 32         }
 33     }
 34 
 35     public void modify(String id) throws Exception {
 36         Session session = HibernateUtil.getSession();
 37         Transaction tx = null;
 38         try {
 39             tx = session.beginTransaction();
 40             log.write("modify():开始事务");
 41             Thread.sleep(500);
 42 
 43             Cat cat = (Cat) session.get(Cat.class, id);
 44 
 45             log.write("modify():查询到cat_name为:" + cat.getCat_name());
 46             Thread.sleep(500);
 47 
 48             cat.setCat_name(cat.getCat_name()+"modify");
 49             log.write("modify():把cat_name改为:" + cat.getCat_name());
 50 
 51             tx.commit();
 52             log.write("modify():提交事务");
 53             Thread.sleep(500);
 54         } catch (StaleObjectStateException e) {
 55             if (tx != null) {
 56                 tx.rollback();
 57             }
 58             e.printStackTrace();
 59             System.out.println("cat_name已被其他事务修改,本事务被撤销,请重新开始modify事务");
 60             log.write("modify():cat_name已被其他事务修改,本事务被撤销");
 61         } catch (RuntimeException e) {
 62             if (tx != null) {
 63                 tx.rollback();
 64             }
 65             throw e;
 66         } finally {
 67             session.close();
 68         }
 69     }
 70 
 71     public void update(String id) throws Exception {
 72         Session session = HibernateUtil.getSession();
 73         Transaction tx = null;
 74         try {
 75             tx = session.beginTransaction();
 76             log.write("update():开始事务");
 77             Thread.sleep(500);
 78 
 79             Cat cat = (Cat) session.get(Cat.class, id);
 80 
 81             log.write("update():查询到cat_name为:" + cat.getCat_name());
 82             Thread.sleep(500);
 83 
 84             cat.setCat_name(cat.getCat_name()+"update");
 85             log.write("update():把cat_name改为:" + cat.getCat_name());
 86 
 87             tx.commit();
 88             log.write("update():提交事务");
 89             Thread.sleep(500);
 90         } catch (StaleObjectStateException e) {
 91             if (tx != null) {
 92                 tx.rollback();
 93             }
 94             e.printStackTrace();
 95             System.out.println("cat_name已被其他事务修改,本事务被撤销,请重新开始update事务");
 96             log.write("update():cat_name已被其他事务修改,本事务被撤销");
 97         } catch (RuntimeException e) {
 98             if (tx != null) {
 99                 tx.rollback();
100             }
101             throw e;
102         } finally {
103             session.close();
104         }
105     }
106     
107     public static void main(String args[]) throws Exception {
108         Cat cat = new Cat();
109         cat.setCat_name("test3@optiLock");
110         HibernateUtil.save(cat);
111         
112         Log log = new Log();
113         String id = cat.getId();
114         Thread modifyThread = new Test_optiLock("modify", log ,id);
115         Thread updateThread = new Test_optiLock("update", log ,id);
116 
117         modifyThread.start();
118         updateThread.start();
119 
120         while (modifyThread.isAlive() || updateThread.isAlive()) {
121             Thread.sleep(100);
122         }
123         log.print();
124     }
125 }
126 
127 class Log {
128     private ArrayList<String> logs = new ArrayList<String>();
129 
130     synchronized void write(String text) {
131         logs.add(text);
132     }
133 
134     public void print() {
135         for (Iterator<String> it = logs.iterator(); it.hasNext();) {
136             System.out.println(it.next());
137         }
138     }
139 }

执行后控制台信息如下:

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

原文地址:https://www.cnblogs.com/xiluhua/p/4381056.html