java – Spring,@Transactional和Hibernate Lazy Loading

前端之家收集整理的这篇文章主要介绍了java – Spring,@Transactional和Hibernate Lazy Loading前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
我正在使用春天的冬眠.我所有的HibernateDAO直接使用sessionFactory.

我有应用层 – >服务层 – > DAO层和所有的集合都是加载的.

所以,问题是在应用程序层(包含GUI / swing)的某个时刻,我使用服务层方法(包含@Transactional注释)加载一个实体,我想使用这个对象的一个​​惰性属性,但是可以直观地看到会话已经关闭

解决这个麻烦的最好办法是什么?

编辑

我尝试使用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最近推出了提取配置文件(除了性能调优之外)是解决这类问题的理想选择.它允许您(在运行时)在不同的加载和初始化策略之间进行选择.

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

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

开始之前:检查抓取的个人资料实际上是否适合您.我没有自己使用它们,看到他们目前仅限于加入提取.在浪费时间实施和接线拦截器之前,请尝试手动设置抓取配置文件,看到它实际上可以解决您的问题.

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

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相关文章