您的位置:首页 > 数据库

hibernate---->悲观锁和乐观锁

2012-09-06 10:31 316 查看
一、悲观锁

悲观锁的实现,通常依赖于数据库机制,在整个过程中将数据锁定,其它任何用户都不能读取或修改

悲观锁的实现:

显式的用户指定"可以通过以下几种方式之一来表示:

调用 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) 

 

 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息