如何控制hibernate延迟加载异常

时间:2013-11-10 14:50:09

标签: hibernate exception lazy-loading

我正在使用 Hibernate和Struts

我们在hibernate中使用延迟加载。

现在在JSP中我面临着延迟加载异常,另一个解决方案就是使用EAGER,但我无法改变其他应用程序的Eager依赖性。

专注于延迟加载任何方式来控制延迟加载异常?

3 个答案:

答案 0 :(得分:1)

默认加载策略是使用LAZY获取关联的集合。建议的解决方案是通过在代码中在运行时覆盖此默认策略来加载关联的集合。 QueryCriteria接口都支持此功能。

例如,如果您有以下实体关联映射:

public class XEntity {
...
private Set<YEntity> yentities;
}
}

然后使用Query界面,关联的yentities可以与XEntity一起提取,如下所示:

String xSelect = "select x from XEntity "
                + "x left join fetch x.yentities "
                + "where x.xName=:xname";
Query query = session.createQuery(xSelect);

Criteria接口,可以这样做:

Criteria criteria = session.createCriteria(XEntity.class);
criteria.setFetchMode("yentities", FetchMode.JOIN);

这两个都会在一次选择中获取关联的yentitiesXEntity

您还可以使用Hibernate#initialize初始化集合:

XEntity xentity = (XEntity) session.get(XEntity.class, id);
Hibernate.initialize(xentity.getYentities());
tx.commit();
session.close();

但最好先使用HQLCriteria查询来获取完整的必需图表。

答案 1 :(得分:0)

避免延迟加载异常的常用方法是使用fetch join。如果您有一个带有延迟加载属性Employee的实体projects,您可以像这样重写查询:

SELECT e FROM Employee e
LEFT JOIN FETCH e.projects

您可能希望在此处使用LEFT JOIN来获取所有员工,无论是否有项目。简单的JOIN FETCH将导致内部联接,仅返回具有项目的员工。

触发加载延迟加载属性的另一种不太明确的方法是在事务提交之前访问它们:

tx.begin(); // for illustration, also works for container managed transactions  
...
Employee emp = // get the employee
emp.getProjects().size();
...
tx.commit();

请注意,调用emp.getProjects()来触发加载是不够的。实际上,您需要执行需要属性值的操作才能触发加载。

我通常更喜欢第一种方法,因为它更清楚地表达了意图。

答案 2 :(得分:0)

只需在hibernate和@NotFound注释中使用事务管理器。

@Entity
public class OurEntity {

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "department")
    @NotFound(action=NotFoundAction.IGNORE)
    private LazyObject lazyObject;

    // ... getters, setters

}

public class SomeOtherClass {

@Autowired
private SessionFactory sessionFactory;

@Transactional(readOnly = false, rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
public LazyObject getSomethingLazy(Long id){

     final OurEntity ourEntity = sessionFactory.getCurrentSession().get(OurEntity.class, id);
     LazyObject lazyObject = null;
     if(ourEntity != null){
         //this will never throw lazy loading exception if Transactional annotation is used
         lazyObject = ourEntity.getLazyObject();
     }
     return lazyObject;
}

和配置:

<bean id="dataSource" class="com.jolbox.bonecp.BoneCPDataSource" destroy-method="close">
   <property name="driverClass"><value>${public.jdbc.driverClassName}</value></property>
   <property name="jdbcUrl"><value>${public.jdbc.url}</value></property>
   <property name="username"><value>${public.jdbc.username}</value></property>
   <property name="password"><value>${public.jdbc.password}</value></property>

   <property name="idleConnectionTestPeriod" value="60"/>
   <property name="idleMaxAge" value="240"/>
   <property name="maxConnectionsPerPartition" value="1"/>
   <property name="minConnectionsPerPartition" value="1"/>
   <property name="partitionCount" value="3"/>
   <property name="acquireIncrement" value="5"/>
   <property name="statementsCacheSize" value="100"/>
   <property name="releaseHelperThreads" value="3"/>
</bean>

<bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">

    <property name="dataSource">
        <ref bean="dataSource" />
    </property>

    <property name="packagesToScan">
        <list>
            <value>packages.to.scan</value>
        </list>
    </property>
    <property name="hibernateProperties">
        <props>
            <prop key="hibernate.dialect">DATABASE.DIALECT.CLASS.PATH</prop>
            <prop key="hibernate.connection.CharSet">utf8</prop>
            <prop key="hibernate.connection.characterEncoding">utf8</prop>
            <prop key="hibernate.connection.useUnicode">true</prop>
        </props>
    </property>
</bean>

<!--Transaction management -->
<bean id="transactionTemplate"
    class="org.springframework.transaction.support.TransactionTemplate">
    <property name="transactionManager" ref="transactionManager" />
</bean>

<!-- Enable the configuration of transactional behavior based on annotations -->
<tx:annotation-driven transaction-manager="transactionManager" />

<!-- Transaction Manager is defined -->
<bean id="transactionManagerPublic" class="org.springframework.orm.hibernate4.HibernateTransactionManager">
   <property name="sessionFactory" ref="sessionFactory"/>
</bean>