Hibernate Session刷新行为

我在一个网络应用程序中使用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的事务结束时没有刷新对象。

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

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

更新[为我解决]:

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

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

我发现:

  1. 问题是由于我进入事务时flushMode设置为flushMode (事务提交时不触发刷新操作);

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

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

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

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

 The Session is flushed before every query. 

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

 true 

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();  em.getTransaction().commit(); } catch(Throwable th) { em.getTransaction().rollback(); //log, rethrow } }