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