[英]Initialize lazy collections
我正在开发一个Struts2 + Spring + Hibernate webapp,我需要在检索一个对象或该对象的集合后初始化一个惰性集合。
用例
我有一个团队模型,其中一个关系急切地被称为员工 (我认为很明显这是一个集合)。 反过来, 员工模型有一个懒惰的关系注册表 ,我只需要一些特定的操作,所以我根本不需要急切地加载它。
现在。 我调用我的teamService
(用Spring注入我的Struts2控制器),以便检索已加载其集合员工的特定teamItem
。 现在是时候为每个员工加载其注册表关系了。
使用employeeService
(也用Spring注入我的Struts2控制器)我调用他的DAO的initializeCollections()
方法,它应该加载延迟集合调用
Hibernate.initialize(employee.getRegistry());
当我执行此操作时, org.hibernate.LazyInitializationException: could not initialize proxy - no Session
引发org.hibernate.LazyInitializationException: could not initialize proxy - no Session
异常。
堆栈跟踪:
at org.hibernate.proxy.AbstractLazyInitializer.initialize(AbstractLazyInitializer.java:167) ~[hibernate-core-3.6.10.Final.jar:3.6.10.Final]
at org.hibernate.Hibernate.initialize(Hibernate.java:414) ~[hibernate-core-3.6.10.Final.jar:3.6.10.Final]
at web.bkgd.simba.dao.registry.RegistryEmployeeDAO.initializeCollections(RegistryEmployeeDAO.java:438) ~[RegistryEmployeeDAO.class:?]
at web.bkgd.simba.service.abstractions.BaseService.initializeCollections(BaseService.java:142) ~[BaseService.class:?]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:1.7.0_79]
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) ~[?:1.7.0_79]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:1.7.0_79]
at java.lang.reflect.Method.invoke(Method.java:606) ~[?:1.7.0_79]
at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:317) ~[spring-aop-4.1.0.RELEASE.jar:4.1.0.RELEASE]
at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:190) ~[spring-aop-4.1.0.RELEASE.jar:4.1.0.RELEASE]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157) ~[spring-aop-4.1.0.RELEASE.jar:4.1.0.RELEASE]
at org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:98) ~[spring-tx-4.1.0.RELEASE.jar:4.1.0.RELEASE]
at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:266) ~[spring-tx-4.1.0.RELEASE.jar:4.1.0.RELEASE]
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:95) ~[spring-tx-4.1.0.RELEASE.jar:4.1.0.RELEASE]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) ~[spring-aop-4.1.0.RELEASE.jar:4.1.0.RELEASE]
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:207) ~[spring-aop-4.1.0.RELEASE.jar:4.1.0.RELEASE]
at com.sun.proxy.$Proxy1302.initializeCollections(Unknown Source) ~[?:?]
at web.bkgd.simba.controller.ajax.agenda.TeamController.doSomething(TeamController.java:177) ~[AjaxTeamController.class:?]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:1.7.0_79]
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) ~[?:1.7.0_79]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:1.7.0_79]
at java.lang.reflect.Method.invoke(Method.java:606) ~[?:1.7.0_79]
at ognl.OgnlRuntime.invokeMethod(OgnlRuntime.java:870) ~[ognl-3.0.6.jar:?]
at ognl.OgnlRuntime.callAppropriateMethod(OgnlRuntime.java:1293) ~[ognl-3.0.6.jar:?]
at ognl.ObjectMethodAccessor.callMethod(ObjectMethodAccessor.java:68) ~[ognl-3.0.6.jar:?]
at com.opensymphony.xwork2.ognl.accessor.XWorkMethodAccessor.callMethodWithDebugInfo(XWorkMethodAccessor.java:117) ~[xwork-core-2.3.24.1.jar:2.3.24.1]
at com.opensymphony.xwork2.ognl.accessor.XWorkMethodAccessor.callMethod(XWorkMethodAccessor.java:108) ~[xwork-core-2.3.24.1.jar:2.3.24.1]
at ognl.OgnlRuntime.callMethod(OgnlRuntime.java:1369) ~[ognl-3.0.6.jar:?]
at ognl.ASTMethod.getValueBody(ASTMethod.java:90) ~[ognl-3.0.6.jar:?]
at ognl.SimpleNode.evaluateGetValueBody(SimpleNode.java:212) ~[ognl-3.0.6.jar:?]
at ognl.SimpleNode.getValue(SimpleNode.java:258) ~[ognl-3.0.6.jar:?]
at ognl.Ognl.getValue(Ognl.java:494) ~[ognl-3.0.6.jar:?]
at ognl.Ognl.getValue(Ognl.java:458) ~[ognl-3.0.6.jar:?]
at com.opensymphony.xwork2.ognl.OgnlUtil$2.execute(OgnlUtil.java:309) ~[xwork-core-2.3.24.1.jar:2.3.24.1]
at com.opensymphony.xwork2.ognl.OgnlUtil.compileAndExecute(OgnlUtil.java:340) ~[xwork-core-2.3.24.1.jar:2.3.24.1]
at com.opensymphony.xwork2.ognl.OgnlUtil.getValue(OgnlUtil.java:307) ~[xwork-core-2.3.24.1.jar:2.3.24.1]
at com.opensymphony.xwork2.DefaultActionInvocation.invokeAction(DefaultActionInvocation.java:423) ~[xwork-core-2.3.24.1.jar:2.3.24.1]
at com.opensymphony.xwork2.DefaultActionInvocation.invokeActionOnly(DefaultActionInvocation.java:287) ~[xwork-core-2.3.24.1.jar:2.3.24.1]
at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:250) ~[xwork-core-2.3.24.1.jar:2.3.24.1]
at web.bkgd.simba.utility.interceptors.SessionCleanInterceptor.intercept(SessionCleanInterceptor.java:86) ~[SessionCleanInterceptor.class:?]
at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:244) ~[xwork-core-2.3.24.1.jar:2.3.24.1]
at org.apache.struts2.interceptor.DeprecationInterceptor.intercept(DeprecationInterceptor.java:41) ~[struts2-core-2.3.24.1.jar:2.3.24.1]
at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:244) ~[xwork-core-2.3.24.1.jar:2.3.24.1]
at org.apache.struts2.interceptor.debugging.DebuggingInterceptor.intercept(DebuggingInterceptor.java:256) ~[struts2-core-2.3.24.1.jar:2.3.24.1]
at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:244) ~[xwork-core-2.3.24.1.jar:2.3.24.1]
at com.opensymphony.xwork2.interceptor.DefaultWorkflowInterceptor.doIntercept(DefaultWorkflowInterceptor.java:167) ~[xwork-core-2.3.24.1.jar:2.3.24.1]
at com.opensymphony.xwork2.interceptor.MethodFilterInterceptor.intercept(MethodFilterInterceptor.java:98) ~[xwork-core-2.3.24.1.jar:2.3.24.1]
at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:244) ~[xwork-core-2.3.24.1.jar:2.3.24.1]
at com.opensymphony.xwork2.validator.ValidationInterceptor.doIntercept(ValidationInterceptor.java:265) ~[xwork-core-2.3.24.1.jar:2.3.24.1]
at org.apache.struts2.interceptor.validation.AnnotationValidationInterceptor.doIntercept(AnnotationValidationInterceptor.java:76) ~[struts2-core-2.3.24.1.jar:2.3.24.1]
at com.opensymphony.xwork2.interceptor.MethodFilterInterceptor.intercept(MethodFilterInterceptor.java:98) ~[xwork-core-2.3.24.1.jar:2.3.24.1]
at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:244) ~[xwork-core-2.3.24.1.jar:2.3.24.1]
at com.opensymphony.xwork2.interceptor.ConversionErrorInterceptor.intercept(ConversionErrorInterceptor.java:138) ~[xwork-core-2.3.24.1.jar:2.3.24.1]
at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:244) ~[xwork-core-2.3.24.1.jar:2.3.24.1]
at com.opensymphony.xwork2.interceptor.ParametersInterceptor.doIntercept(ParametersInterceptor.java:229) ~[xwork-core-2.3.24.1.jar:2.3.24.1]
at com.opensymphony.xwork2.interceptor.MethodFilterInterceptor.intercept(MethodFilterInterceptor.java:98) ~[xwork-core-2.3.24.1.jar:2.3.24.1]
at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:244) ~[xwork-core-2.3.24.1.jar:2.3.24.1]
at com.opensymphony.xwork2.interceptor.ParametersInterceptor.doIntercept(ParametersInterceptor.java:229) ~[xwork-core-2.3.24.1.jar:2.3.24.1]
at com.opensymphony.xwork2.interceptor.MethodFilterInterceptor.intercept(MethodFilterInterceptor.java:98) ~[xwork-core-2.3.24.1.jar:2.3.24.1]
at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:244) ~[xwork-core-2.3.24.1.jar:2.3.24.1]
at com.opensymphony.xwork2.interceptor.StaticParametersInterceptor.intercept(StaticParametersInterceptor.java:191) ~[xwork-core-2.3.24.1.jar:2.3.24.1]
at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:244) ~[xwork-core-2.3.24.1.jar:2.3.24.1]
at org.apache.struts2.interceptor.MultiselectInterceptor.intercept(MultiselectInterceptor.java:73) ~[struts2-core-2.3.24.1.jar:2.3.24.1]
at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:244) ~[xwork-core-2.3.24.1.jar:2.3.24.1]
at org.apache.struts2.interceptor.DateTextFieldInterceptor.intercept(DateTextFieldInterceptor.java:125) ~[struts2-core-2.3.24.1.jar:2.3.24.1]
at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:244) ~[xwork-core-2.3.24.1.jar:2.3.24.1]
at org.apache.struts2.interceptor.CheckboxInterceptor.intercept(CheckboxInterceptor.java:91) ~[struts2-core-2.3.24.1.jar:2.3.24.1]
at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:244) ~[xwork-core-2.3.24.1.jar:2.3.24.1]
at org.apache.struts2.interceptor.FileUploadInterceptor.intercept(FileUploadInterceptor.java:253) ~[struts2-core-2.3.24.1.jar:2.3.24.1]
at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:244) ~[xwork-core-2.3.24.1.jar:2.3.24.1]
at com.opensymphony.xwork2.interceptor.ModelDrivenInterceptor.intercept(ModelDrivenInterceptor.java:100) ~[xwork-core-2.3.24.1.jar:2.3.24.1]
at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:244) ~[xwork-core-2.3.24.1.jar:2.3.24.1]
at com.opensymphony.xwork2.interceptor.ScopedModelDrivenInterceptor.intercept(ScopedModelDrivenInterceptor.java:141) ~[xwork-core-2.3.24.1.jar:2.3.24.1]
at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:244) ~[xwork-core-2.3.24.1.jar:2.3.24.1]
at com.opensymphony.xwork2.interceptor.ChainingInterceptor.intercept(ChainingInterceptor.java:145) ~[xwork-core-2.3.24.1.jar:2.3.24.1]
at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:244) ~[xwork-core-2.3.24.1.jar:2.3.24.1]
at com.opensymphony.xwork2.interceptor.PrepareInterceptor.doIntercept(PrepareInterceptor.java:171) ~[xwork-core-2.3.24.1.jar:2.3.24.1]
at com.opensymphony.xwork2.interceptor.MethodFilterInterceptor.intercept(MethodFilterInterceptor.java:98) ~[xwork-core-2.3.24.1.jar:2.3.24.1]
at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:244) ~[xwork-core-2.3.24.1.jar:2.3.24.1]
at com.opensymphony.xwork2.interceptor.I18nInterceptor.intercept(I18nInterceptor.java:139) ~[xwork-core-2.3.24.1.jar:2.3.24.1]
at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:244) ~[xwork-core-2.3.24.1.jar:2.3.24.1]
at org.apache.struts2.interceptor.ServletConfigInterceptor.intercept(ServletConfigInterceptor.java:164) ~[struts2-core-2.3.24.1.jar:2.3.24.1]
at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:244) ~[xwork-core-2.3.24.1.jar:2.3.24.1]
at com.opensymphony.xwork2.interceptor.AliasInterceptor.intercept(AliasInterceptor.java:193) ~[xwork-core-2.3.24.1.jar:2.3.24.1]
at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:244) ~[xwork-core-2.3.24.1.jar:2.3.24.1]
at com.opensymphony.xwork2.interceptor.ExceptionMappingInterceptor.intercept(ExceptionMappingInterceptor.java:189) [xwork-core-2.3.24.1.jar:2.3.24.1]
at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:244) [xwork-core-2.3.24.1.jar:2.3.24.1]
at web.bkgd.simba.utility.interceptors.LoginInterceptor.intercept(LoginInterceptor.java:113) [LoginInterceptor.class:?]
at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:244) [xwork-core-2.3.24.1.jar:2.3.24.1]
at org.apache.struts2.impl.StrutsActionProxy.execute(StrutsActionProxy.java:54) [struts2-core-2.3.24.1.jar:2.3.24.1]
at org.apache.struts2.dispatcher.Dispatcher.serviceAction(Dispatcher.java:564) [struts2-core-2.3.24.1.jar:2.3.24.1]
at org.apache.struts2.dispatcher.ng.ExecuteOperations.executeAction(ExecuteOperations.java:81) [struts2-core-2.3.24.1.jar:2.3.24.1]
at org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter.doFilter(StrutsPrepareAndExecuteFilter.java:99) [struts2-core-2.3.24.1.jar:2.3.24.1]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241) [catalina.jar:7.0.61]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208) [catalina.jar:7.0.61]
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:220) [catalina.jar:7.0.61]
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:122) [catalina.jar:7.0.61]
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:505) [catalina.jar:7.0.61]
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:170) [catalina.jar:7.0.61]
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:103) [catalina.jar:7.0.61]
at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:950) [catalina.jar:7.0.61]
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:116) [catalina.jar:7.0.61]
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:423) [catalina.jar:7.0.61]
at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1079) [tomcat-coyote.jar:7.0.61]
at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:620) [tomcat-coyote.jar:7.0.61]
at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:318) [tomcat-coyote.jar:7.0.61]
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145) [?:1.7.0_79]
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615) [?:1.7.0_79]
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) [tomcat-coyote.jar:7.0.61]
at java.lang.Thread.run(Thread.java:745) [?:1.7.0_79]
编辑01-12-2015
我试图按照Predrag Maric的回答,我做了一些编辑,因为似乎仍然无法正常工作。
所以:
- 在View模式中实现Open Session
没门。 此解决方案可能会导致非常深的关系加载,特别是对于JSON序列化。 当然我总是可以定义<param name="includeProperties">
标签并加载我需要的东西,但我仍然有点害怕表演。
- 在第一个服务中初始化您需要的任何内容
这就是重点。 我已经改变了我的动作和DAO结构以实现这个功能。 我已经使用了一些反射来创建一个通用的方法,我可以在我的应用程序的每个DAO中使用。
它的工作原理非常简单:
例
INPUT:
第一个字符串的方法只调用Hibernate.initialize()
方法,第二个字符串拆分字符串以加载:
initializeRelations(relation.class, relation, "childRelation.grandChildRelation");
initializeRelations(childRelation.class, childRelation, "grandChildRelation");
在这里你有代码:
TEAM DAO
在从数据库加载团队bean或团队bean列表之后调用这些方法
/**
* Initialize relations. This method returns true if a correct
* initialization of the relation has been made by hibernate, false in any
* other case. If the relations object is a List, the method recursively
* call himself in order to initialize every single instance of the list.
* If the relations string contains a "." it means that a grandchild
* relation has to be loaded.
*
* @param beanClass
* @param model
* @param relations
* @return boolean
*/
public boolean initializeRelations(Class beanClass, BaseModel model, Object relations) {
// Check if relations is a List
if (relations instanceof List) {
// Recursively call initializeRelations
for (String relation : (List<String>) relations) {
return initializeRelations(beanClass, model, relation);
}
} else if (relations instanceof String) {
// If relations contains "." then a grandChild relation has to be loaded.
if (((String) relations).contains(".")) {
String[] childRelations = ((String) relations).split("\\.");
// Initialize the child relation
Object newChildRelations = initializeRelation(beanClass, model, childRelations[0]);
if (newChildRelations == null) {
return false;
} else if (newChildRelations instanceof BaseModel) {
initializeRelations(newChildRelations.getClass(), model, (Object[]) Arrays.copyOfRange(childRelations, 1, childRelations.length));
} else if (newChildRelations instanceof List) {
for (Object newChildRelation : childRelations) {
initializeRelations(newChildRelation.getClass(), model, (Object[]) Arrays.copyOfRange(childRelations, 1, childRelations.length));
}
}
} else {
Object newChildRelations = initializeRelation(beanClass, model, (String) relations);
return newChildRelations == null;
}
}
return false;
}
private Object initializeRelation(Class beanClass, BaseModel model, String relation) {
try {
for (PropertyDescriptor pd : Introspector.getBeanInfo(beanClass).getPropertyDescriptors()) {
if (pd.getReadMethod() != null && !"class".equals(pd.getName()) && relation.toLowerCase().equals(pd.getName().toLowerCase()) && pd.getReadMethod().invoke(model) == null) {
Hibernate.initialize(pd.getReadMethod().invoke(model));
return pd.getReadMethod().invoke(model);
}
}
} catch (IntrospectionException ex) {
LOG.warn("Cannot initialize ralation", ex);
} catch (HibernateException | IllegalAccessException | IllegalArgumentException | InvocationTargetException ex) {
LOG.warn("Cannot initialize ralation", ex);
}
return null;
}
但是我在日志中看到的只是加载了第一个关系
[DEBUG] 01-12-2015 14:06:52 Controller - relation: Employee{data1="data1", data2="data2", data3="data3", data4="data4", data5="data5"}
[DEBUG] 01-12-2015 14:06:52 Controller - child: [!!!model.Registry_$$_javassist_17@75ce9b7d=>org.hibernate.LazyInitializationException:could not initialize proxy - no Session!!!]
是的,您可以使用Hibernate.initialize()
来初始化延迟关系,但这需要一个活动的Hibernate会话。 你是
teamService
(一个事务) employeeService
(另一个事务) 第一次调用后,您的实体与会话分离(如果我错了,请更正我,我假设您已在服务层上配置了事务),因此失败。 你也应该
对于2.,如果此服务用于其他不需要employee.registry
初始化的地方,则可以使用参数来控制初始化
teamService.getTeam(id, init);
// and then in getTeam()
if (init) {
Hibernate.initialize(employee.getRegistry());
}
为了使其更通用,您可以创建一个InitConfig
类,该类将传递给需要此类行为的每个服务。 您只需在需要时添加特定参数即可。
public class InitConfig {
...
private boolean initRegistry;
...
}
teamService.getTeam(id, initConfig);
// and then in getTeam()
if (initConfig.getInitRegistry()) {
Hibernate.initialize(employee.getRegistry());
}
几个月前我遇到了一些问题。 我已经解决了它在我的会话工厂构建器中设置参数的问题。
尝试将参数“hibernate.enable_lazy_load_no_trans”设置为您的hibernate配置。
sfBuilder.getProperties().put("hibernate.enable_lazy_load_no_trans",
"true");
这个参数解决了我的问题。 希望能帮助到你。
编辑:谨慎使用。 看看这篇文章 。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.