我在网络应用程序中使用Spring和Hibernate,
将SessionFactory注入到DAO bean中,然后通过webservicecontext在Servlet中使用此DAO。
DAO方法是事务性的,在我使用的方法之一... getCurrentSession()。save(myObject);
一个servlet使用传递的对象调用此方法。
更新似乎不会立即刷新,查看数据库中的更改大约需要5秒钟。调用DAO更新方法的servlet方法只需几分之一秒即可完成。
DAO的@Transactional方法完成后,可能不会发生冲洗?它似乎不是一个规则 [我已经看到了]。
然后问题是:在每个DAO方法之后如何强制会话刷新? 这可能不是一件好事,但谈到Service层,一些方法必须以立即刷新结束,而Hibernate Session行为是不可预测的。
那么如何保证我的@Transactional方法在该方法代码的最后一行之后保留所有更改?
getCurrentSession().flush() is the only solution?
P.S。我在某处看到@Transactional与DB Transaction相关联。方法返回,必须提交事务。 我没有看到这种情况发生。
答案 0 :(得分:5)
一旦“顶级”@Transactional方法完成(即从你的servlet调用的方法),那么应该提交事务,并且默认的Hibernate行为是在提交时刷新。
听起来好像发生了奇怪的事情,你应该做一些调查。
调查您的日志,特别是我会在事务管理器上将日志记录级别设置为DEBUG,以确切了解事务管理器正在执行的操作。
另外,为hibernate设置登录(将show_sql设置为true):当发生刷新时,这将输出到System.out,这可能会给你一些线索。
如果您发现任何有趣的事情,请回报。
答案 1 :(得分:3)
Amaze我认为这是一个可以解决这种确切情况的确切答案,每当你需要在每次交易后完全刷新会话限制时,你可以使用FlushMode.ALWAYS
来表示特定的DAO。
@Autowired
private SessionFactory sessionFactory;
@Before
public void myInitMethod(){
sessionFactory.getCurrentSession().setFlushMode(FlushMode.ALWAYS);
}
ALWAYS
flushmode不是优选的,因为它很昂贵,但是根据您的要求,您可以根据不同的要求使用不同的flushmode进行多个会话工厂。
答案 2 :(得分:2)
我也有这个问题! 我正在使用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()
我在我的问题中挖了很多东西,找到了问题的根源和解决方法。
如果我理解的话,我有一个间歇性问题,其中一些交易被正确关闭(即休眠会话被刷新)而其他一些事务没有。
我发现:
问题是由于我在进入事务时将flushMode
设置为FlushMode.MANUAL
(在事务提交时不触发刷新操作);
这反过来是由于Spring和ZK之间发生了一些令人讨厌的事情(糟糕的交易全部来自ZK的作曲家 - 如果你不了解ZK,他们是从servlet调用的,大致相当于Struts的行动);
准确的问题在于Spring的OpenSessionInViewFilter
没有正确地与ZK的过滤器通信:OpenSessionInViewFilter
提供的Hibernate会话没有正确设置其刷新模式。单个ZK编写器运行良好(我已经从一些JUnit测试中测试过它),以及单独的OpenSessionInViewFilter
(我使用WebApplicationContextUtils
从一个普通的Servlet测试过它。)
结论:我在作曲家的每个@Transactional方法结束时调用session.flush()
,我将迁移到Vaadin(看起来要简化得多)。
答案 3 :(得分:0)
根据您的特殊需要(在每个DAO方法调用时刷新),您可以将会话刷新模式设置为FlushMode.ALWAYS。来自hibernate文档:
The Session is flushed before every query.
答案 4 :(得分:0)
设置" hibernate.transaction.flush_before_completion"属性为真可能有帮助。
<prop key="hibernate.transaction.flush_before_completion">true</prop>
https://docs.jboss.org/hibernate/orm/4.3/manual/en-US/html_single/
&#34;如果启用,会话将在事务完成前阶段自动刷新。内置和自动会话上下文管理是首选,请参见第2.5节“上下文会话”&#34;。
答案 5 :(得分:0)
出于性能原因,我不建议全局使用 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
}
}