当前位置: 首页 > 面试题库 >

使用Hibernate和Spring实现乐观锁

施彬彬
2023-03-14
问题内容

我试图按顺序实施乐观锁定,以避免丢失更新情况。在我的应用程序中,当两个用户获取相同的记录,而第一个用户通过一些更改对其进行更新时。查看相同记录的第二个用户看不到此更改,并且他自己进行了一些更改并更新了该记录。因此,第一人称更改丢失。为了防止这种情况,我写了以下内容,但问题仍然存在。我是这个概念的新手,无法发现问题。

我试图通过阅读doc
11.3.4 来实现这一目标。自定义自动版本控制部分。

  • 配置文件
        <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:mvc="http://www.springframework.org/schema/mvc"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:tx="http://www.springframework.org/schema/tx"
    xsi:schemaLocation="
    http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
    http://www.springframework.org/schema/tx
    http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
    http://www.springframework.org/schema/mvc
    http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd">

    <tx:annotation-driven transaction-manager="txManager"/>

    <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
      <property name="dataSource" ref="dataSource"/>
    </bean>

    <bean id="hibernateTemplate" class="org.springframework.orm.hibernate3.HibernateTemplate">
      <property name="sessionFactory" ref="sessionFactory"/>
    </bean>

    <bean id="sessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
      <property name="dataSource" ref="dataSource"/>
      <property name="annotatedClasses">
        <list>
            <value>server.bo.Dept</value>
            <value>server.bo.Emp</value>
        </list>
      </property>
      <property name="hibernateProperties">
        <props>
            <prop key="hibernate.dialect">org.hibernate.dialect.SQLServer2008Dialect</prop>
            <prop key="hibernate.show_sql">false</prop>
        </props>
      </property>
    </bean>
    <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
      <property name="driverClassName" value="net.sourceforge.jtds.jdbc.Driver"/>
      <property name="url" value="${db.url}"/>
      <property name="username" value="${db.username}"/>
      <property name="password" value="${db.password}"/>
    </bean>
    <bean id="deptDAO" class="server.dao.DeptDAOImpl">
      <property name="hibernateTemplate" ref="hibernateTemplate"/>
    </bean>
    </beans>
  • 实体类
        @Entity
    @Table(name = "Dept")
    @org.hibernate.annotations.Entity(dynamicUpdate = true,optimisticLock = OptimisticLockType.ALL)
    public class Dept{
        @Id
        @GeneratedValue(strategy = GenerationType.AUTO)
        @Column(name = "ID")
        Long id;

        @OneToMany(cascade = CascadeType.REMOVE, fetch = FetchType.EAGER, mappedBy = "deptId")
        @Fetch(FetchMode.SELECT)
        @OrderBy(value = "id DESC")
        List<Emp> Emplist;

        public Dept() {}
        // Getters and setters
    }
  • DAO Impl
        public class DeptDAOImpl extends HibernateDaoSupport implements DeptDAO {
        @Transactional(readOnly = true, propagation = Propagation.REQUIRED, isolation = Isolation.REPEATABLE_READ)
        public Dept getDeptById(Long id) {
                Object param[] = new Object[]{id};
                String  query = "select d from Dept d where d.id=? and d.deleted='0'";
                List<Dept> deptDetailsList = getHibernateTemplate().find(query,param);
                Dept deptDetails = null;
                if(deptDetailsList !=null && deptDetailsList .size()>0)
                    deptDetails = (Dept)deptDetailsList.get(0);
                return deptDetails ;
        }

        @Transactional(readOnly = false, propagation = Propagation.REQUIRED, isolation = Isolation.REPEATABLE_READ)
        public long updateDept(Dept dept) {
                if (dept.getId() == null) { 
                    getSession().save(dept);
                } else {
                    getSession().update(dept);
                }
                if (dept.getEmplist() != null) {
                        final int size = dept.getEmplist().size();
                        for (int i = size - 1; i >= 0; i--) { 
                            Emp emp = dept.getEmplist().get(i);
                            if (emp.getDeptId() == null) {
                                emp.setDeptId(dept.getId());
                        }
                        if (RecordStatus.NEW.equals(emp.getRecordStatus())) {
                            getSession().save(emp);
                        } else if (RecordStatus.DELETED.equals(emp.getRecordStatus())) {
                            getSession().delete(emp);
                        } else if (RecordStatus.MODIFIED.equals(emp.getRecordStatus())) {
                            getSession().update(emp);
                        }
                    }
            }
            return dept.getId();
        }
    }

提前致谢


问题答案:

JPA / Hibernate
Optmistic锁定的工作方式是使用某个字段来存储上次修改的版本(例如,时间戳,long),然后将会话中实体的版本与数据库中的实体进行比较,以查看是否可以保存更改。

为此,您需要在实体中使用@Version注释字段。

参见以下示例。

http://www.javacodegeeks.com/2012/11/jpahibernate-version-based-optimistic-
concurrency-control.html

为了使它在Web应用程序中起作用,需要进一步考虑,但是,好像两个人加载了相同的实体进行编辑,然后过一会儿提交他们的编辑,他们很可能都会成功,除非您使用某种长时间运行的会话,否则该实体正在编辑的文件将从表单提交的数据库中重新加载,填充和保存。

例如,修订版1中的实体

  • 用户1加载以进行编辑:版本为1
  • 用户2进行编辑加载:修订为1
  • 用户2提交表单:已加载实体(在r1处),绑定了字段,已保存实体:修订版为2。
  • 用户1提交表单:已加载实体(在r2处),绑定了字段,已保存实体:修订版为3。

因此,要使此工作正常进行,您可以看一下提交一个隐藏字段的表单,该表单在存储实体修订版本时将其存储。因此,在上面的最后一步,当用户1提交时,修订字段将被设置回1,并且更新将失败,因为数据库中的记录在r2处。



 类似资料:
  • 我有一个带有和的微服务。我使用注释对中的表执行操作。我遇到的问题是保存操作花费了太多的时间,所以我希望读取操作不被它阻塞。注意,保存是通过持久化实体来执行的。 当前,在所有并发保存操作完成之前,所有读取操作都不会返回结果,这意味着表被锁定。相反,我希望实现乐观锁定。我怎样才能做到呢?

  • 我读到我们可以使用<code>@version</code>在hibernate中使用version字段实现乐观锁定。然后,通过阅读悲观锁定,我知道了<code>org.hidbernate。LockMode</code>类,它有一些选项,如<code>LockMod。我们可以在中指定的OPTIMISTICetc。 所以我的问题是我是否需要同时使用和?

  • 我有一个用Tapestry5(javawebframework)和Hibernate制作的web应用程序。现在我尝试添加乐观锁定。所以我添加了一个版本属性,乐观的锁定可以工作,所以这很容易,很快。 但是,由于我的web应用程序使用“每个请求一个会话”模式,我不确定利用这种乐观锁定的最佳方式是什么。 发生了什么: 用户 A 打开包含表单的页面,该表单加载了来自实体 A(版本 1)的值。 UserB打

  • 我有一个这样的实体: 我有一个生成HQL的代码: 执行更新的代码: 问题: 乐观锁在这里出现吗?在上述情况下,Hibernate是否会自动处理乐观锁定(运行HQL且没有会话)? 如果上述情况不正确,我需要自己实现:我阅读了Hibernate文档,其中说,我需要用注释一个字段。但是我应该专门为此在表中添加这个新字段吗?或者我可以为注释指定任何现有字段?这里有什么特殊处理吗? 在乐观锁定期间抛出的异常

  • 1. 前言 在锁一节中,我们从粒度和管理两个角度来阐述了锁。如果你还不熟悉锁,请先阅读该小节,再来进行本小节的学习。 本小节我们将继续深挖锁,以开发者和实战的角度来谈锁。 2. 为什么需要锁 2.1 什么是数据竞争 在本节的开头,我们来谈一谈为什么开发程序需要使用锁?如果你有一点并发编程的基础,又或者对多线程有一点熟悉,那么你肯定知道答案,那就是数据竞争。 2.2 数据竞争实例 我们举一个生活的例

  • 悲观锁:假定会发生并发冲突,屏蔽一切可能违反数据完整性的操作 乐观锁:假设不会发生并发冲突,只在提交操作时检查是否违反数据完整性。 乐观锁与悲观锁的具体区别: http://www.cnblogs.com/Bob-FD/p/3352216.html