【问题标题】:Hibernate updates database though all the service methods marked as read-only by spring transaction management通过spring事务管理标记为只读的所有服务方法Hibernate更新数据库
【发布时间】:2010-08-11 04:25:32
【问题描述】:

我之前已经发布过这个问题,但由于线程有点旧,我想我没有得到回复,很抱歉duplicating 但我的问题与春季交易有关。

我在 Spring 事务管理方面遇到了类似的问题。我正在使用休眠作为 ORM 框架。下面是我使用spring事务管理的应用程序的spring配置文件的摘录。

<context:annotation-config/>
    <context:property-placeholder location="classpath:spring.properties"/>

    <tx:annotation-driven transaction-manager="transactionManager"/>
    <tx:advice id="txAdvice">
        <tx:attributes>
            <tx:method name="find*" read-only="true"/>
            <tx:method name="get*" read-only="true"/>
            <tx:method name="create*" rollback-for="Exception"/>
            <tx:method name="update*" rollback-for="Exception"/>
            <tx:method name="remove*" rollback-for="Exception"/>
        </tx:attributes>
    </tx:advice>
    <aop:config>
        <aop:pointcut id="ServiceOperation" expression="execution(* com.shaikh.demo.*Service.*(..))" />
        <aop:advisor advice-ref="txAdvice" pointcut-ref="ServiceOperation"/>
    </aop:config>

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

我所有的 *Service 类都由 @Transactional 注释进行注释。

在我的休眠 DTO 类中,我正在修改每个 get* 方法的返回值,如下所示,因为我想删除所有非 ascii 字符。数据库中的数据用于只读目的,仅用于列出记录,在此之前我需要删除造成问题的非 ascii 字符。数据库是 Oracle 11g。

例如对于属性 accountNumber

public String getAccountNumber(){
      return StringHelper.removeNonAscii(this.accountNumber);
}

我读到我们正在更改 DTO 对象的状态并使其变脏,因此休眠将这些脏对象刷新到数据库中。我可以在日志中看到更新语句。

我的问题是:

1.) 我正在使 DTO 对象变脏,但我已将 get* 相关方法标记为只读,因此休眠如何刷新对数据库的更改。

2.) 如何在不更改数据库数据的情况下解决与此非 Ascii 字符相关的问题。我错过了什么吗?

【问题讨论】:

    标签: hibernate spring transactions dto


    【解决方案1】:

    在我的休眠 DTO 类中,我正在修改每个 get* 方法的返回值,如下所示,因为我想删除所有非 ascii 字符。

    即时修改返回值不会修改实体本身。换句话说,它不应该变脏。

    我读到我们正在更改 DTO 对象的状态并使其变脏,因此休眠将这些脏对象刷新到数据库中。

    那么你在某个时候调用了一些 setter。

    我正在使 DTO 对象变脏,但我已将 get* 相关方法标记为只读,因此休眠如何刷新对数据库的更改。

    我怀疑您是否在 getter 中进行任何数据库访问(我认为对事务部分存在一些误解)。

    如何在不更改数据库数据的情况下解决与此非 Ascii 字符相关的问题。我错过了什么吗?

    正如我所写的,我认为访问 getter 不会使您的实体变脏,一定还有其他原因。但如果它们真的是只读的,您可以将它们标记为不可变(参见5.1.3. Class)。

    【讨论】:

    • 即时修改返回值不会修改实体本身。换句话说,它不应该变脏。这就是我的想法,所以我更新了 DTO 类以删除非 ascii 字符。我将尝试调试我的事务代码以及这些不可变的东西。感谢大家的回复,我们会尽快回复您。
    【解决方案2】:

    来自Hibernate Reference

    每当你将一个对象传递给 save() 时, update() 或 saveOrUpdate(),以及 每当您使用检索对象时 加载(),获取(),列表(),迭代()或 scroll(),该对象被添加到 Session的内部缓存。

    随后调用 flush() 时, 该对象的状态将是 与数据库同步。如果你 不希望此同步 发生,或者如果您正在处理一个巨大的 对象数量和需要管理 高效内存,evict() 方法 可用于移除对象和 它的收藏来自一级 缓存。

    我的猜测是,即使您的 get* 方法是只读的,它们仍然会将持久对象放在 Hibernate Session 上,这些对象会在某个时候被刷新,从而保存您的更改。

    您能否在 get* 方法的末尾简单地 evict() 您的 DTO 对象,以便在休眠会话有机会刷新对这些对象的任何更改之前将它们与休眠会话分离?

    【讨论】:

    • 您能否在 get* 方法的末尾简单地 evict() 您的 DTO 对象我正在通过 dao 从数据库中获取对象列表,我认为这种 evict 方法适用于对象级别,所以我不想要遍历这个列表并对每个对象应用 evict 方法。
    【解决方案3】:

    您好,我能够按照 Pascal Thivent 的建议通过在 .hbm.xml 文件中将 DTO 类标记为不可变来修复我的问题,感谢您的帮助。但我不确定为什么标记为只读的事务会发生这种情况。

    【讨论】:

      猜你喜欢
      • 2014-07-08
      • 1970-01-01
      • 2021-03-10
      • 2012-10-16
      • 1970-01-01
      • 2012-05-06
      • 2021-06-07
      • 2016-12-02
      • 1970-01-01
      相关资源
      最近更新 更多