【问题标题】:Issue with hibernate/Spring transaction management休眠/Spring事务管理问题
【发布时间】:2011-11-16 06:33:10
【问题描述】:

我遇到了 Spring Transaction 管理的问题。我正在使用休眠作为 ORM 框架。下面是我的事务管理春天。

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


  <bean id="abstractDao"
      class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean" abstract="true" lazy-init="true">
    <property name="transactionManager">
        <ref bean="transactionManager"/>
    </property>
    <property name="transactionAttributeSource">
        <ref bean="transactionAttributeSource"/>
    </property>   
    <property name="postInterceptors">
      <list>
        <ref bean="finderIntroductionAdvisor"/>
      </list>
    </property>       
</bean>
   <bean id="abstractService"
      class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean" abstract="true" lazy-init="true">
    <property name="transactionManager">
        <ref bean="transactionManager"/>
    </property>
    <property name="transactionAttributeSource">
        <ref bean="transactionAttributeSource"/>
    </property>   
</bean>

我基本上遵循 here 中提到的 genericDao 方法,因此 My DaoObject 用于获取域对象,并且服务类具有 DAO 对象来处理它们。

我面临的问题:我正在查询一个大型数据集并将结果加载到服务类中的列表中。我已将服务类标记为 @transactional(readonly ="true")。

为了处理一些要求,我已将盒装原语的所有吸气剂更改为

  @Column(name = "students")
public Long getStudents() {
    if(students== null){
        return 0l;
    }
    return this.students;
}

每当我通过命名查询加载所有数据集时。随后会触发多个更新查询以更新数据集。 我对其进行了调试并知道这是由于 transaction.commit 而发生的。因为休眠将我的实体视为肮脏的。

有没有办法避免这种情况。我知道 Flushmode.never 可能会有所帮助,但在我的应用程序中,seesion 对象没有暴露,所以我无权访问它。还有其他方法或一些映射更改可以帮助我吗?

【问题讨论】:

  • 当我看到hibernate在仅仅做一个查询之后试图发出更新或删除的唯一情况是映射错误,这使得hibernate认为某些元素被删除或更新了。我只是提到这一点,因为这很有可能是根本问题。
  • 我可以建议更改问题的标题吗?由于 SO 被认为是未来的参考,因此问题既可浏览又可搜索非常好。
  • 是的,比尔当然可以

标签: java hibernate spring transactions


【解决方案1】:

问题在于

if(students== null){ return 0l; }

当 Hibernate 获取您的实体时,它们在 students 字段上都具有空值。在提交时,检查它们是否脏时,getStudents() 返回 0,这与存储在数据库中的值不同。因此,Hibernate 认为它们很脏,并继续进行更新。

如果它适合您的要求,将studentfield 的类型更改为原始类型long 而不是Long 可能会有所帮助。请注意,从长远来看,这将导致将该列中的所有null 更新为 0。

也许您应该在其他地方处理该要求,并让 getter 摆脱这种担忧。

【讨论】:

  • 但这会抛出 Nullpointer,因为 DB 中的学生为 null 并且休眠将尝试将 null 设置为原语
  • 这绝对是正确的答案。被这个咬过一次,这是我不会很快忘记的一课。
  • @digitaljoel 我也不会。具有所有字段 null 的可嵌入将整个可嵌入转换为 null 让我开心了好几天 :) 无论如何,我认为 axtavt's answer 是正确的解决方案。跨度>
  • 只是补充一下,另一种可能性是实现PropertyAccessor
  • 好吧,也许我应该说,“这绝对是正确的诊断”,axtavt 的回答看起来也不错。
【解决方案2】:

除了 Xavi López 的回答之外,另一种选择是将 Hibernate 处理的持久性属性与符合您要求的瞬态属性分开。例如如下:

@Column(name = "students")
public Long getStudentsInternal() {
    return students;
}

@Transient
public Long getStudents() {
    if (students == null) {
        return 0l;
    }
    return students;
}

您还可以通过将注释移动到它们来配置 Hibernate 以使用字段而不是属性,它也将解决您的问题(请注意,注释的放置应该与实体的所有字段一致,或者您可以使用 @987654322 @ 配置排除):

@Column(name = "students")
private Long students;

public Long getStudents() {
    if (students == null) {
        return 0l;
    }
    return students;
}

【讨论】:

    猜你喜欢
    • 2017-05-09
    • 2014-08-25
    • 1970-01-01
    • 1970-01-01
    • 2011-02-15
    • 1970-01-01
    • 1970-01-01
    • 2012-08-08
    • 2015-10-15
    相关资源
    最近更新 更多