• 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

  • 相关阅读:
    Linux进程和线程
    Vim编辑器
    Java多线程编程(七)线程状态、线程组与异常处理
    Java多线程编程(六)单例模式与多线程
    Integer to Roman
    Container With Most Water
    Regular Expression Matching
    Palindrome Number
    c/c++获取硬盘序列号
    String to Integer (atoi)
  • 原文地址:https://www.cnblogs.com/xiluhua/p/4381056.html
Copyright © 2020-2023  润新知