首先要知道以下的注意点:
1 更新丢失的问题:
用两个testCase一起运行模拟多线程并发
两个线程同时修改一个对象 会产生更新丢失的问题
慢的那个保留了以前的东西
使得快的修改的东西没有作用
2 解决办法解决并发问题:
1 悲观锁 (一般不用 )
* 是Hibernate基于数据库的机制来实现的,此时hibernate3和4所实现的机制是不一样的
* hibernate3是基于同步的机制实现的(类似Java锁 必须等第一个结束 其他的在排队 效率很低)
* hibernate4若是两个同时修改 那么会抛出异常
* 2 乐观锁
* 在数据库中增加一个version的字段来实现的,每一次修改都会让这个字段的数字+1,
* 在读取的时候 会根据version这个版本的数据来读取
* 这样如果并发修改就会抛异常 只要提示再次重新更新就可以 正常
3 使用悲观锁的方法:
//加使用了UPGRADE就加上了锁(悲观)
Student stu=(Student)session.load(Student.class,1,LockOptions.UPGRADE);
4乐观锁的使用方法:
在类中 和xml文件中添加字段version 并不使用悲观锁
* 更新一次 数据库中的version字段值就+1
* 当慢的那个线程在更新时 发现自己之前获取的version值和 现在数据库中的不一样(已经更新)
* 那么就会抛异常 停止更新
* org.hibernate.StaleObjectStateException:
* Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect)
* 注意:version 一定要加在ID后面 property前面
* 我们只要让慢的重新更新就可以(service重新调用即可(抛出对应异常的话))
Student.java
public class Student
{
private int id;
private String name;
private String sex;
private Classroom classroom;
private int version;
public int getVersion()
{
return version;
}
public void setVersion(int version)
{
this.version = 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 String getSex()
{
return sex;
}
public void setSex(String sex)
{
this.sex = sex;
}
public Classroom getClassroom()
{
return classroom;
}
public void setClassroom(Classroom classroom)
{
this.classroom = classroom;
}
}
xml文件
<hibernate-mapping package="com.itany.model">
<class name="Student" table="t_stu">
<!-- <cache usage="read-only" /> -->
<id name="id">
<generator class="native"></generator>
</id>
<!-- 注意:version 一定要加在ID后面 property前面 -->
<version name="version" />
<property name="name" />
<property name="sex" />
<many-to-one name="classroom" column="cid" fetch="join" />
</class>
</hibernate-mapping>
测试用例:
public class TestBingFa
{
@Test
public void update01()
{
/*用两个testCase一起运行模拟多线程并发
* 两个线程同时修改一个对象 会产生更新丢失的问题
* 慢的那个保留了以前的东西
* 使得快的修改的东西没有作用
*
* 重要:!!!2种解决方法可以解决并发的问 题:
* 1 悲观锁 (一般不用 )
* 是Hibernate基于数据库的机制来实现的,此时hibernate3和4所实现的机制是不一样的
* hibernate3是基于同步的机制实现的(类似Java锁 必须等第一个结束 其他的在排队 效率很低)
* hibernate4若是两个同时修改 那么会抛出异常
* 2 乐观锁
* 在数据库中增加一个version的字段来实现的,每一次修改都会让这个字段的数字+1,
* 在读取的时候 会根据version这个版本的数据来读取
* 这样如果并发修改就会抛异常 只要提示再次重新更新就可以 正常
*
*/
Session session = null;
Transaction trans = null;
try
{
session = HibernateUtil.openSession();
trans=session.beginTransaction();
//加使用了UPGRADE就加上了锁(悲观)
Student stu=(Student)session.load(Student.class,1,LockOptions.UPGRADE);
stu.setName("三哥1");
trans.commit();
}
catch (HibernateException e)
{
trans.rollback();
e.printStackTrace();
}
finally
{
if (null != session)
HibernateUtil.closeSession(session);
}
}
@Test
public void update02()
{
/*
*
*/
Session session = null;
Transaction trans = null;
try
{
session = HibernateUtil.openSession();
trans=session.beginTransaction();
Student stu=(Student)session.load(Student.class,1,LockOptions.UPGRADE);
stu.setSex("女");
trans.commit();
}
catch (HibernateException e)
{
trans.rollback();
e.printStackTrace();
}
finally
{
if (null != session)
HibernateUtil.closeSession(session);
}
}
//-----------------------------乐观锁-------------------------------------
@Test
public void update03()
{
/*
* 在类中 和xml文件中添加字段version 并不使用悲观锁
* 更新一次 数据库中的version字段值就+1
* 当慢的那个线程在更新时 发现自己之前获取的version值和 现在数据库中的不一样(已经更新)
* 那么就会抛异常 停止更新
* org.hibernate.StaleObjectStateException:
* Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect)
*
* 我们只要让慢的重新更新就可以(service重新调用即可(抛出对应异常的话))
*/
Session session = null;
Transaction trans = null;
try
{
session = HibernateUtil.openSession();
trans=session.beginTransaction();
Student stu=(Student)session.load(Student.class,1);
stu.setName("三哥2");
trans.commit();
}
catch (HibernateException e)
{
trans.rollback();
e.printStackTrace();
}
finally
{
if (null != session)
HibernateUtil.closeSession(session);
}
}
@Test
public void update04()
{
/*
*
*/
Session session = null;
Transaction trans = null;
try
{
session = HibernateUtil.openSession();
trans=session.beginTransaction();
Student stu=(Student)session.load(Student.class,1);
stu.setSex("女");
trans.commit();
}
catch (HibernateException e)
{
trans.rollback();
e.printStackTrace();
}
finally
{
if (null != session)
HibernateUtil.closeSession(session);
}
}
}