blo*_*low 11 java spring hibernate lazy-loading
我正在使用spring + hibernate.我所有的HibernateDAO直接使用sessionFactory.
我有应用层 - >服务层 - > DAO层,并且所有集合都是懒惰加载的.
所以,问题是在应用层(包含GUI/swing)的某个时候我使用服务层方法(包含@Transactional注释)加载实体,我想使用这个对象的lazly属性,但是很明显会话已经关闭.
解决这个问题的最佳方法是什么?
编辑
我尝试使用MethodInterceptor,我的想法是为我的所有实体编写一个AroundAdvice并使用注释,例如:
// Custom annotation, say that session is required for this method
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface SessionRequired {
// An AroundAdvice to intercept method calls
public class SessionInterceptor implements MethodInterceptor {
public Object invoke(MethodInvocation mi) throws Throwable {
bool sessionRequired=mi.getMethod().isAnnotationPresent(SessionRequired.class);
// Begin and commit session only if @SessionRequired
if(sessionRequired){
// begin transaction here
}
Object ret=mi.proceed();
if(sessionRequired){
// commit transaction here
}
return ret;
}
}
// An example of entity
@Entity
public class Customer implements Serializable {
@Id
Long id;
@OneToMany
List<Order> orders; // this is a lazy collection
@SessionRequired
public List<Order> getOrders(){
return orders;
}
}
// And finally in application layer...
public void foo(){
// Load customer by id, getCustomer is annotated with @Transactional
// this is a lazy load
Customer customer=customerService.getCustomer(1);
// Get orders, my interceptor open and close the session for me... i hope...
List<Order> orders=customer.getOrders();
// Finally use the orders
}
Run Code Online (Sandbox Code Playgroud)
你觉得这可行吗?问题是,如何在没有xml文件的情况下为我的所有实体注册这个拦截器?有一种方法可以使用注释吗?
Hibernate 最近引入了获取配置文件(除了性能调整之外),它非常适合解决此类问题。它允许您(在运行时)在不同的加载和初始化策略之间进行选择。
编辑(添加了有关如何使用拦截器设置获取配置文件的部分):
开始之前:检查获取配置文件是否确实适合您。我自己没有使用过它们,并且发现它们目前仅限于加入提取。在浪费时间实现和连接拦截器之前,请尝试手动设置获取配置文件,看看它是否真正解决了您的问题。
在 Spring 中设置拦截器的方法有很多(根据偏好),但最直接的方法是实现 MethodInterceptor(参见http://static.springsource.org/spring/docs/3.0.x/spring-框架参考/html/aop-api.html#aop-api-advice-around)。让它有一个用于您想要的获取配置文件的设置器和一个用于 Hibernate 会话工厂的设置器:
public class FetchProfileInterceptor implements MethodInterceptor {
private SessionFactory sessionFactory;
private String fetchProfile;
... setters ...
public Object invoke(MethodInvocation invocation) throws Throwable {
Session s = sessionFactory.openSession(); // The transaction interceptor has already opened the session, so this returns it.
s.enableFetchProfile(fetchProfile);
try {
return invocation.proceed();
} finally {
s.disableFetchProfile(fetchProfile);
}
}
}
Run Code Online (Sandbox Code Playgroud)
最后,在 Spring 配置中启用拦截器。这可以通过多种方式完成,并且您可能已经有了可以将其添加到的 AOP 设置。请参阅http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/aop.html#aop-schema。
如果您是 AOP 新手,我建议首先尝试“旧”ProxyFactory 方式(http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/aop-api .html#aop-api-proxying-intf) 因为它更容易理解它是如何工作的。以下是一些可帮助您入门的示例 XML:
<bean id="fetchProfileInterceptor" class="x.y.zFetchProfileInterceptor">
<property name="sessionFactory" ref="sessionFactory"/>
<property name="fetchProfile" ref="gui-profile"/>
</bean>
<bean id="businessService" class="x.y.x.BusinessServiceImpl">
<property name="dao" .../>
...
</bean>
<bean id="serviceForSwinGUI"
class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="proxyInterfaces" value="x.y.z.BusinessServiceInterface/>
<property name="target" ref="businessService"/>
<property name="interceptorNames">
<list>
<value>existingTransactionInterceptorBeanName</value>
<value>fetchProfileInterceptor</value>
</list>
</property>
</bean>
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
17312 次 |
最近记录: |