0

I am using Hibernate and Struts

we are using lazy loading in hibernate.

now in JSP I am facing the lazy loading exception, the other solution is that to use EAGER, but I can not change to Eager dependency of other applications.

focusing on lazy loading any way to control lazy loading exception?

3 Answers 3

1

The default loading strategy is to use LAZY fetching for associated collections. And the recommended solution is to load the associated collections by overriding this default strategy at runtime in code. Both the Query and Criteria interfaces support this.

For example, if you have below entity association mapping:

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

then with Query interface, the associated yentities can be fetched along with the XEntity as this:

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

and with Criteria interface, this can be done as this:

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

Both of these two will fetch the associated yentities along with the XEntity, in a single select.

You can also use Hibernate#initialize to initialize the collection:

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

But its a good practice to fetch the complete required graph in the first place, using HQL or Criteria queries.

Sign up to request clarification or add additional context in comments.

Comments

0

A common way to avoid lazy loading exceptions is to use fetch joins. If you have an entity Employee with lazily loaded attribute projects, you would rewrite the query like this:

SELECT e FROM Employee e
LEFT JOIN FETCH e.projects

You probably want to use a LEFT JOIN here to get all Employees, with or without projects. A simple JOIN FETCH would result in an inner join, returning only employees with projects.

A different, less explicit way to trigger loading of lazily loaded attributes is to access them before the transaction commits:

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

Please note that it would not be enough to call emp.getProjects() to trigger loading. You actually need to perform an operation that needs the value of the attribute to trigger loading.

I would generally prefer the first approach because it communicates the intent much clearer.

Comments

0

Just use transaction manager in hibernate and @NotFound annotation.

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

and configuration:

<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>

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.