hibernate--悲观锁-乐观锁的并发问题

本文探讨了在 Hibernate 中遇到的并发问题,如更新丢失,并介绍了悲观锁和乐观锁两种解决方案。悲观锁通过数据库机制实现,可能导致效率低下,而乐观锁依赖于版本字段,在并发修改时抛出异常,需要重新尝试更新。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

首先要知道以下的注意点:

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);
        }
    }
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值