一、悲观锁
悲观锁的实现,通常依赖于数据库机制,在整个过程中将数据锁定,其它任何用户都不能读取或修改
悲观锁的实现:
显式的用户指定"可以通过以下几种方式之一来表示:
-
调用 Session.load()的时候指定锁定模式(LockMode)。
-
调用Session.lock()。
-
调用Query.setLockMode()。
package com.wsz.test; import junit.framework.TestCase; import org.hibernate.LockMode; import org.hibernate.Session; import org.hibernate.Transaction; import com.wsz.entity.HibernateUtils; import com.wsz.entity.Products; public class Test extends TestCase { public void testSave() { Session session = null; Transaction tx = null; Products products = null; try { session = HibernateUtils.getSession(); tx = session.beginTransaction(); products=new Products(); products.setName("脑白金"); products.setTotalnumber(1000); session.save(products); tx.commit(); } catch (Exception e) { e.printStackTrace(); tx.rollback(); } finally { HibernateUtils.closeSession(session); } } public void test1() { Products products = new Products(); Session session = HibernateUtils.getSession(); session.beginTransaction(); //悲观锁的实现 products = (Products) session.load(products.getClass(), 1,LockMode.UPGRADE); System.out.print(products.getName()); System.out.println(products.getTotalnumber()); products.setTotalnumber(products.getTotalnumber()-200); session.getTransaction().commit(); } public void test2() { Products products = new Products(); Session session = HibernateUtils.getSession(); session.beginTransaction(); products = (Products) session.load(products.getClass(), 1,LockMode.UPGRADE); System.out.print(products.getName()); System.out.println(products.getTotalnumber()); products.setTotalnumber(products.getTotalnumber()-200); session.getTransaction().commit(); } }
使用悲观锁,lazy属性失效,立即发出sql。
二、乐观锁
大多数基于数据版本记录机制(version)实现,一般是在数据库表中加入一个version字段,读取数据时将版本号一同读出,之后更新数据时版本号加一,如果提交数据时版本号小于或等于数据表中的版本号,则认为数据是过期的,否则给予更新。
Products.hbm.xml
<hibernate-mapping> <class name="com.wsz.entity.Products" table="t_products" optimistic-lock="version"> <id name="id"> <generator class="native" /> </id> <version name="version"/> <property name="name" /> <property name="totalnumber" /> </class> </hibernate-mapping>
数据库表多了一个version字段
开始version=0
如果更新后 version=1,由数据库自动更新。
Products.java
package com.wsz.entity; public class Products { private int id; private String name; private int totalnumber; private int version; public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getTotalnumber() { return totalnumber; } public void setTotalnumber(int totalnumber) { this.totalnumber = totalnumber; } public int getVersion() { return version; } public void setVersion(int version) { this.version = version; } }
Test.java
package com.wsz.test; import junit.framework.TestCase; import org.hibernate.Session; import org.hibernate.Transaction; import com.wsz.entity.HibernateUtils; import com.wsz.entity.Products; public class Test extends TestCase { public void testSave() { Session session = null; Transaction tx = null; Products products = null; try { session = HibernateUtils.getSession(); tx = session.beginTransaction(); products=new Products(); products.setName("naobaijin"); products.setTotalnumber(1000); session.save(products); tx.commit(); } catch (Exception e) { e.printStackTrace(); tx.rollback(); } finally { HibernateUtils.closeSession(session); } } public void test1() { Products products = new Products(); Session session = HibernateUtils.getSession(); session.beginTransaction(); //悲观锁的实现 products = (Products) session.load(products.getClass(), 1); System.out.print(products.getName()); System.out.println(products.getTotalnumber()); products.setTotalnumber(products.getTotalnumber()-200); session.getTransaction().commit(); } public void test2() { Products products = new Products(); Session session = HibernateUtils.getSession(); session.beginTransaction(); products = (Products) session.load(products.getClass(), 1); System.out.print(products.getName()); System.out.println(products.getTotalnumber()); products.setTotalnumber(products.getTotalnumber()-200); session.getTransaction().commit(); } }
使用悲观锁,lazy不会失效,不会立即发出sql
更新时发出的sql语句Hibernate: update t_products set version=?, name=?, totalnumber=? where id=? and version=?,
如果test1更新了,在commit设置断点,没有提交,test2更新了。此时test1往下运行,当前的version 小于数据库的version ,会生成如下的异常。
10:48:59,260 ERROR AbstractFlushingEventListener:301 - Could not synchronize database state with session
org.hibernate.StaleObjectStateException: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect): [com.wsz.entity.Products#1]
at org.hibernate.persister.entity.AbstractEntityPersister.check(AbstractEntityPersister.java:1699)