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