Java 初始化惰性集合
我正在开发一个Struts2+Spring+HibernateWebApp,在检索一个对象或该对象的集合后,我需要初始化一个惰性集合 用例 我有一个团队模型,该模型中有一个名为员工的关系(我认为这显然是一个集合)。反过来,employee模型有一个惰性关系registry,我只需要它来执行一些特定的操作,所以我根本不需要急切地加载它 现在。我调用我的Java 初始化惰性集合,java,hibernate,lazy-loading,Java,Hibernate,Lazy Loading,我正在开发一个Struts2+Spring+HibernateWebApp,在检索一个对象或该对象的集合后,我需要初始化一个惰性集合 用例 我有一个团队模型,该模型中有一个名为员工的关系(我认为这显然是一个集合)。反过来,employee模型有一个惰性关系registry,我只需要它来执行一些特定的操作,所以我根本不需要急切地加载它 现在。我调用我的teamService(使用Spring注入我的Struts2控制器),以检索已加载其收藏员工的特定teamItem。现在是为每个员工加载其注册表关
teamService
(使用Spring注入我的Struts2控制器),以检索已加载其收藏员工的特定teamItem
。现在是为每个员工加载其注册表关系的时候了
使用employeeService
(也将其注入到我的Struts2控制器中,使用Spring)调用他的DAO的initializeCollections()
方法,该方法应加载惰性集合调用
Hibernate.initialize(employee.getRegistry());
执行此操作时,会出现org.hibernate.LazyInitializationException:无法初始化代理-不会引发会话
异常
堆栈跟踪:
- 我做错什么了吗
- 有没有其他方法来加载这个惰性集合
标记并加载所需的内容,但我仍然有点害怕性能
- beanClass:团队
- 模型:未加载关系的团队
- 关系:列表:{“关系”,“关系.子关系.孙子关系”}
Hibernate.initialize()
方法,第二个字符串的方法拆分字符串以加载:
- realization,返回
初始化设置(relation.class,relation,“childRelation.grandrelation”)代码>
- childRelation,返回
初始化设置(childRelation.class,childRelation,“孙子关系”)代码>
- 孙辈关系李>
/**
* 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;
}
是的,您可以使用
Hibernate.initialize()
初始化惰性关系,但这需要一个活动的Hibernate会话。你是
teamService
(一个事务)employeeService
,并显示第一次调用的结果(另一个事务)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\u lazy\u load\u no\u trans”设置到hibernate配置中
sfBuilder.getProperties().put("hibernate.enable_lazy_load_no_trans",
"true");
这个参数解决了我的问题。希望能有帮助
编辑:
小心使用。签出。我仍然收到一个
org.hibernate.LazyInitializationException:无法初始化代理-没有会话代码>错误。你能看一看我的编辑吗?“但我还是有点害怕表演。”是的,但在你尝试和分析之前……很多关于OSIV(至少是Spring实现)的批评实际上是不正确的。这是最简单、最透明的解决方案,不需要全部或什么都不做:按照“做最简单的事情”的原则,在OSIV开销太大的情况下,尝试并进一步优化它。只需注意:在初始化
方法中,当关系
无效时,您不会处理这种情况一个数组,但您在那里传递了一个数组:(Object[])array.copyOfRange(…)
它永远不会是数组。或者更好。。。“parent”方法调用initializeRatings()
,总是创建一个列表。只有递归调用initializeRelations()
时,才会使用relations instanceOf String
语句。但是谢谢你的来信。你的回答解决了我的问题。网络上对此参数的看法各不相同,当然,N+1问题总是指日可待,但atm似乎没有很多问题。谢谢你@RodrigoAlmeida
public class InitConfig {
...
private boolean initRegistry;
...
}
teamService.getTeam(id, initConfig);
// and then in getTeam()
if (initConfig.getInitRegistry()) {
Hibernate.initialize(employee.getRegistry());
}
sfBuilder.getProperties().put("hibernate.enable_lazy_load_no_trans",
"true");