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会话被刷新)而其他一些事务没有。
我发现:
-
问题是由于我进入事务时
flushMode
设置为flushMode
(事务提交时不触发刷新操作); -
这反过来是由于Spring和ZK之间发生了一些令人讨厌的事情(糟糕的交易全部来自ZK的composer php – 如果你不了解ZK,他们是从servlet调用的,大致相当于Struts的行为);
-
确切的问题在于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 } }