Hibernate - 多次启动的相同操作变得越来越慢

时间:2016-06-22 14:00:51

标签: java performance hibernate session

我的Hibernate存在性能问题。

Hibernate : 3.2.6.ga
JDK : jdk1.6.0_45

我有一个函数,它被注释@Transactionnal,它链接到一个EntityManager。

这个函数在循环中调用,所以我有:

for (Item i : itemList) 
{
saveIt(i);
}

如果我将它推出5/10/20次就可以了,过程时间似乎没有增加。 但如果我发射300/400次,“保存”的时间越来越慢...... 我监视了java内存,我没有看到一些奇怪的东西。

所以我发现一些文章谈论了Flush / Clean魔术解决方案。 我试过它和Hourra,它有效。

for (Item i : itemList) 
    {
    saveit(i);
    cleanMySession();
    }

但对我来说这很奇怪,因为我认为@Transactionnal注释管理了所有这些东西,特别是当我在这个循环之外没有做任何与Hibernate相关的事情时......也许我有点迷失了......

最后一个问题:这种解决方法是否安全?

注意:实际上,saveIt函数在数据操作方面相当庞大,因此处理时间非常重要且不得增加。

编辑 - 补充信息:

我在cleanSession函数中停止了调试模式:

public void cleanSession() {
    Session session = (Session) em.getDelegate();
    session.flush();
    session.clear(); 
}

这是堆栈:

MyServiceImpl.cleanSession() line: 177  
GeneratedMethodAccessor216.invoke(Object, Object[]) line: not available 
DelegatingMethodAccessorImpl.invoke(Object, Object[]) line: 25  
Method.invoke(Object, Object...) line: 597  
AopUtils.invokeJoinpointUsingReflection(Object, Method, Object[]) line: 319 
JdkDynamicAopProxy.invoke(Object, Method, Object[]) line: 196   
$Proxy40.cleanSession() line: not available 
MyAction.doSave() line: 814 
StrutsStack...

所以是的,我看到了一些代理,但对我而言,这个代理来自Spring Injection,而不是来自Hibernate。

编辑N°2:

是的我使用OpenSessionInView过滤器

<filter>
    <filter-name>Spring OpenEntityManagerInViewFilter</filter-name>
    <filter-class>
        org.springframework.orm.jpa.support.OpenEntityManagerInViewFilter
    </filter-class>
</filter>

1 个答案:

答案 0 :(得分:0)

方法cleanMySession()在你放置它的地方(在for循环中,但在saveIt()方法之外)的事实表明你在启动for循环之前已经打开了一个事务。结果,你在for循环中执行的所有操作只在一个tx中完成,只有一个会话的大小会继续增长,从而减慢flush操作(脏检查)。

在调用saveIt()之前,您需要重构服务调用以确保不存在任何交易。

要确定不需要的事务处于打开状态的位置,只需在for循环的开头设置一个断点,使用运行时到达那里,然后查看堆栈跟踪。当您开始看到$ Proxyxxx类时,下一个方法将是打开事务的方法。

它在堆栈中看起来像那样:

at ... <- the method with @Transactional annotation here ->
at java.lang.reflect.Method.invoke(Method.java:498)
at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:310)
at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:182)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:149)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:106)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:171)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:204)
at com.sun.proxy.$Proxy452.handle(Unknown Source)
...

如果您配置的@Transactional以外的其他方面,您可能会遇到未使用@Transactional注释的方法的代理,只需继续查看堆栈调用

编辑: 整个Http请求将由过滤器打开一个tx:查看它就像使用@Transactional注释Controller(包括视图生成)一样。

这个过滤器被认为是错误的(看看Why is Hibernate Open Session in View considered a bad practice?),但如果您的应用程序很大,删除它可能会很复杂和痛苦。

您的解决方法应该有效。

如果你需要多次提交,你可以查看@Transactional(propagation = Propagation.REQUIRES_NEW) ...但是这样,每个请求都会占用几个与数据库的连接(1个用于过滤器+ 1个每个嵌套级别为{{1}因为当遇到'requires_new'方法时池中没有更多的连接,可能会在中间失败