我的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>
答案 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'方法时池中没有更多的连接,可能会在中间失败