繁体   English   中英

Hibernate Session刷新行为[和Spring @Transactional]

[英]Hibernate Session flush behaviour [ and Spring @Transactional ]

我在一个网络应用程序中使用Spring和Hibernate,

SessionFactory被注入到DAO bean中,然后这个DAO通过webservicecontext在Servlet中使用。

DAO方法是事务性的,在我使用的方法之一... getCurrentSession()。save(myObject);

一个servlet使用传递的对象调用此方法。

更新似乎不会立即刷新,大约需要5秒才能看到数据库中的更改。 调用DAO更新方法的servlet方法需要几分之一秒才能完成。

DAO的@Transactional方法完成后,可能不会发生冲洗? 它似乎不是一个规则 [我已经看到了]。

那么问题是:在每个DAO方法之后如何强制会话刷新? 这可能不是一件好事,但谈到Service层,一些方法必须以立即刷新结束,而Hibernate Session行为是不可预测的。

那么如何保证我的@Transactional方法在该方法代码的最后一行之后保留所有更改?

 getCurrentSession().flush() is the only solution?

ps我在某处看到@Transactional与DB Transaction相关联。 方法返回,必须提交事务。 我没有看到这种情况发生。

一旦“顶级”@Transactional方法完成(即从你的servlet调用的方法),那么应该提交事务,并且默认的Hibernate行为是在提交时刷新。

听起来好像发生了奇怪的事情,你应该做一些调查。

调查您的日志,特别是我会在事务管理器上将日志记录级别设置为DEBUG,以确切了解事务管理器正在执行的操作。

另外,为hibernate设置登录(将show_sql设置为true):当发生刷新时,这将输出到System.out,这可能会给你一些线索。

如果您发现任何有趣的事情,请回报。

Amaze我认为这是一个可以解决这种确切情况的确切答案,只要你需要在每次事务后完全刷新会话限制,就可以使用FlushMode.ALWAYS进行特定的DAO。

@Autowired
private SessionFactory sessionFactory;

@Before
public void myInitMethod(){
  sessionFactory.getCurrentSession().setFlushMode(FlushMode.ALWAYS);
}

ALWAYS flushmode是不可取的,因为它很昂贵,但是根据您的要求,您可以根据不同的要求使用不同的flushmode进行多个会话工厂。

我也有这个问题! 我正在使用Spring注释事务(@Transactional),我正在使用一些方法实际上在做session.flush(),而其他没有!

从我的调试日志中我得到:

transaction completed on session with on_close connection release mode; be sure to close the session to release JDBC resources!

必须从Spring TransationManager调用session.close(),但我不确定发生了什么:我仔细检查了我的Spring配置,我无法争论为什么会发生这种情况。 我进一步调查,我将重新发布任何提示,但如果有人有一些有用的建议,我将非常感激:o)

更新:问题似乎与hibernate session flush mode = MANUAL有关:它在Spring的事务结束时没有刷新对象。

您可以使用以下内容验证当前的刷新模式:

SessionFactoryUtils.getSession(mySessionFactory(), false).getCurrentSession().getFlushMode()


更新[为我解决]:

我在我的问题中挖了很多东西,找到了问题的根源和解决方法。

如果我理解的话,我有一个间歇性问题,其中一些事务正确关闭(即hibernate会话被刷新)而其他一些事务没有。

我发现:

  1. 这个问题是由于flushMode设置为FlushMode.MANUAL当我进入交易(即当事务提交不会触发刷新操作);

  2. 这反过来是由于Spring和ZK之间发生了一些令人讨厌的事情(糟糕的交易都是来自ZK的作曲家 - 如果你不了解ZK,他们是从servlet调用的,大致相当于Struts的行为);

  3. 确切的问题在于Spring的OpenSessionInViewFilter与ZK的过滤器没有正确通信: OpenSessionInViewFilter提供的Hibernate会话没有正确设置其刷新模式。 单个ZK编写器运行良好(我已经从一些JUnit测试中测试过),以及单独的OpenSessionInViewFilter (我使用WebApplicationContextUtils从一个普通的Servlet中测试过它)。

结论:我在作曲家的每个@Transactional方法结束时调用session.flush() ,我将迁移到Vaadin(看起来要简化得多)。

将“hibernate.transaction.flush_before_completion”属性设置为true可能会有所帮助。

<prop key="hibernate.transaction.flush_before_completion">true</prop>

https://docs.jboss.org/hibernate/orm/4.3/manual/en-US/html_single/
“如果启用,会话将在事务完成前阶段自动刷新。首选内置和自动会话上下文管理,请参见第2.5节”上下文会话“。

出于性能原因,我不建议全局使用hibernate.transaction.flush_before_completion

或者,您可以自己管理交易:

@PersistenceContext
private EntityManager em;
....
public void save(){
    try
    {         
        em.getTransaction().begin();                

        <update database>

        em.getTransaction().commit();                        
    }
    catch(Throwable th) {
        em.getTransaction().rollback();
        //log, rethrow
    }        
}

根据您的特殊需要(在每个DAO方法调用时刷新),您可以将会话刷新模式设置为FlushMode.ALWAYS。 从hibernate文档:

The Session is flushed before every query.

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM