gpt4 book ai didi

java - Spring,@Transactional 和 Hibernate 延迟加载

转载 作者:IT老高 更新时间:2023-10-28 13:47:22 27 4
gpt4 key购买 nike

我正在使用 spring + hibernate。我所有的 HibernateDAO 都直接使用 sessionFactory。

我有应用层 -> 服务层 -> DAO 层,所有集合都是延迟加载的。

所以,问题是有时在应用程序层(包含 GUI/swing)中,我使用服务层方法(包含 @Transactional 注释)加载实体,并且我想使用该对象的惰性属性,但是显然 session 已经关闭。

解决这个问题的最佳方法是什么?

编辑

我尝试使用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
}

你认为这行得通吗?问题是,如何在 xml 文件中为我的所有实体注册此拦截器?有没有办法通过注释来做到这一点?

最佳答案

Hibernate 最近引入了 fetch 配置文件,它(除了性能调整之外)是解决此类问题的理想选择。它允许您(在运行时)在不同的加载和初始化策略之间进行选择。

http://docs.jboss.org/hibernate/core/3.5/reference/en/html/performance.html#performance-fetching-profiles

编辑(添加了关于如何使用拦截器设置提取配置文件的部分):

开始之前:检查获取配置文件是否真的适合您。我自己没有使用过它们,并且看到它们目前仅限于加入获取。在您浪费时间实现和连接拦截器之前,请尝试手动设置 fetch 配置文件,看看它是否确实解决了您的问题。

在 Spring 中有很多方法可以设置拦截器(根据偏好),但最直接的方法是实现 MethodInterceptor(参见 http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/aop-api.html#aop-api-advice-around)。让它有一个你想要的获取配置文件的 setter 和 Hibernate session 工厂的 setter :

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);
}
}
}

最后,在 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>

关于java - Spring,@Transactional 和 Hibernate 延迟加载,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4207510/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com