前言:题目有点大了(#>.<),主要就是讨论一下,在使用JPA或者Hibernate的时候(JPA虽然有Hibernate实现,但是还是拆开来说),多表关联加载时机方案的选择的问题。Lazy给很多开发带来困扰,也有很多文章讲解了这些问题,下面是我个人的解决思路和解决方案。
关键词: JPA Hibernate 动态代理 Aop
会话管理
无论是使用JPA或者Hibernate在延迟加载处理中,我们关心的问题无非就是,Session或者EntityManager什么时候打开,什么时候关闭!而解决延迟加载的问题核心在于解决Session或者EntityManager的开关时效管理。
视图层(JPA)
在WEB项目中,基于Filter接口规范来处理,配合Spring使用,在Spring ORM的支持包中已经有解决方案:
OpenEntityManagerInViewFilter
1. 在entity中的@OneToMany、@OneToOne等中设置fetch = FetchType.LAZY
2. 标准的Filter,在web.xml配置即可
3. OpenEntityManagerInViewFilter处理的是Spring通过在ServletContext 中载入配置,通过WebApplicationContextUtils.getWebApplicationContext(ServletContext sc)方法获得ApplicationContext,如果想要自行载入构建的ApplicationContext被OpenEntityManagerInViewFilter处理,需要修改其源代码。
OpenEntityManagerInViewInterceptor
这个Interceptor使用在Spring MVC的结构,使用Spring MVC的可以在applicationContext-*.xml中定义注入即可,它的ref指向EntityManagerFactory ,它也是SimpleUrlHandlerMapping的interceptors属性的list之一,使用Spring MVC的开发人员可以看一下,配置很方便。
视图层(Hibernate)
Hiberate和JPA在Spring中的解决方案是非常类似的。
OpenSessionInViewFilter
1. 必须在Hibernate的配置文件*.hbm.xml中,对class定义lazy="true"或者在many-to-one、
one-to-one映射关心中定义lazy="proxy"。
2. 标准的filter配置,在web.xml中
3. OpenSessionInViewFilter处理的是Spring通过在ServletContext 中载入配置,通过WebApplicationContextUtils.getWebApplicationContext(ServletContext sc)方法获得ApplicationContext,如果想要自行载入构建的ApplicationContext被OpenSessionInViewFilter处理,需要修改其源代码。
OpenSessionInViewInterceptor
这个Interceptor使用在Spring MVC的结构,使用Spring MVC的可以在applicationContext-*.xml中定义注入即可,它的ref指向SessionrFactory ,它也是SimpleUrlHandlerMapping的interceptors属性的list之一
服务层
动态代理(JPA)
使用动态代理AOP结构,来管理EntityManager,这种方案不依赖于容器,在后台服务、测试中都可以良好使用。先看代码:
OpenEntityManagerHandler.java
演示
接口
ITask.java
实现
ITaskImpl.java
使用
运行结果
是不是很简单!
深入
以上的方案不修改的Service/DAO模型,侵入性小,测试方便,但是有一些局限性。更良好的方案可以将OpenEntityManagerHandler进行一些修改,
1. 加入private String FACTORY_NAME=DEFAULT_ENTITYMANGER_FACTORY,修改获取EntityManagerFactory的方法。
2. 在applicationContext-*.xml中配置bean,并ref指向EntityManagerFactory的bean。
3. 修改你的Service/DAO模型,引入OpenEntityManagerHandler。
留给有兴趣的自己研究,修改一下。
补充
Hiberate的解决方案和JPA非常类似,不再重复了。
使用IBatis
不是开玩笑,标准并不能决定一切,JPA和Hiberante也不是持久层的唯一解决方案(JDO等其他不用再考虑了,慢慢的退出舞台吧)!
Ibatis严格来讲不是一个标准ORM框架(真的不太喜欢用框架这个词,头大^.^),如果你本人的SQL造诣比较精深,无论是新项目的开发或者老项目的改造Ibatis都能给你不错的惊喜!
Ibatis延迟加载的开关参数是lazyLoadingEnabled,具体内容参考官方文档,开发者本身SQL水平的高低直接影响Ibatis的使用优劣。
Ibatis现在是apache的顶级项目http://ibatis.apache.org/,文档(有中文的,好像是夏新或者曹晓刚翻译的,有点记得不太清楚了),范例应有尽有,自己去Happy吧。
范例运行
范例中是一个简单的动态代理运行的例子,其中把载入Spring和JPA、Hiberante的依赖去掉了,让大家可以看一下结构,真正配合Spring、JPA/Hiberante使用,需要大家自己增添代码,感兴趣的自己丰富一下代码,希望对你有所启发。
总结
文中提到了四种解决方案,
第一、 使用OpenEntityManagerInViewFilter/OpenSessionInViewFilter,在Spring MVC结构中还可以更方便简洁的使用 OpenEntityManagerInViewInterceptor/OpenSessionInViewInterceptor。
第二、 使用非注入的AOP的结构,应用动态代理,不依赖于任何容器。
第三、 配合Spring使用,需要修改Service/DAO模型,引入自实现的OpenEntityManagerInterceptor/OpenSessionInterceptor
第四、 使用Ibatis。(这个貌似不能算方案#>.<)
ORM框架关于Lazy的解决方案
xml 代码
xml 代码
java 代码
java 代码
java 代码
java 代码
java 代码