org.hibernate.LazyInitializationException: не удалось лениво инициализировать набор ролей (Hibernate + Spring)

У меня есть веб-приложение SpringMVC+Hibernate со следующими файлами:

applicationContext.xml

    <bean id="dataSource" destroy-method="close" class="org.apache.commons.dbcp.BasicDataSource">
    <property name="driverClassName" value="org.postgresql.Driver"/>
    <property name="url" value="jdbc:postgresql://localhost:5432/db"/>
    <property name="username" value="kjhkjkj"/>
    <property name="password" value="dsfa@efe45"/>
</bean>

<bean id="txManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
    <property name="sessionFactory" ref="hibernateSessionFactory"/>
</bean>

<bean id="transactionProxy" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
    <property name="transactionManager" ref="txManager"/>
    <property name="transactionAttributes">
        <props>
            <prop key="*">PROPAGATION_REQUIRED</prop>
        </props>
    </property>
    <property name="target">
        <bean class="dao.DocumentViewDao">
            <property name="sessionFactory" ref="hibernateSessionFactory"/>
        </bean>
    </property>
    <property name="proxyTargetClass" value="true"/>
</bean>

<bean id="hibernateSessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
    <property name="dataSource" ref="dataSource"/>
    <property name="mappingResources">
        <list>
    <value>orm/Document.hbm.xml</value>
    <value>orm/UploadedDocument.hbm.xml</value>
    <!-- More resource files go here -->
        </list>
    </property>
    <property name="hibernateProperties">
        <value>
            hibernate.dialect = org.hibernate.dialect.PostgreSQLDialect
            hibernate.show_sql = true
            hibernate.format_sql = true
            hibernate.generate_statistics = true
            hibernate.cache.use_query_cache = true
            hibernate.cache.use_second_level_cache = true
            hibernate.cache.provider_class = org.hibernate.cache.EhCacheProvider
            hibernate.query.substitutions = true 't', false 'f'
        </value>
    </property>
</bean>

<bean id="documentViewDao" class="dao.DocumentViewDao">
    <property name="sessionFactory" ref="hibernateSessionFactory"/>
</bean>

дао.DocumentViewDao

@Transactional
public class DocumentViewDao extends HibernateDaoSupport
{
public List all ( )
        throws HibernateException
{
    Session session = this.getSessionFactory ( ).getCurrentSession ( );

    return session.createQuery ( new StringBuilder ( 35 )
                    .append ( "SELECT d.id AS id, d.identifier AS identifier, d.title AS title, u.version AS version, u.effectFrom AS effectFrom " )
                    .append ( "FROM Document AS d " )
                    .append ( "LEFT OUTER JOIN d.uploadedDocumentsById AS u " )
                    .append ( "WITH u.isCurrent = true" )
                    .toString ( ) )
            .setCacheable ( true )
            .setResultTransformer( Transformers.ALIAS_TO_ENTITY_MAP )
            .list ( );
}

public Document getDocument ( int documentId )
        throws HibernateException
{
    Session session = this.getSessionFactory ( ).getCurrentSession ( );

    Document document = null;

    Query q = session.createQuery ( "FROM IsoDocument AS d " +
                                    "LEFT OUTER JOIN FETCH d.uploadedDocumentsById " +
                                    "WHERE d.id = :documentId"
    );
    q.setParameter ( "documentId", documentId );
    q.setCacheable ( true );
    document = ( Document ) q.uniqueResult ( );

    return document;
}
}

контроллер.DocumentController

public class DocumentController implements Controller
{   
    public ModelAndView handleRequest ( HttpServletRequest request, HttpServletResponse response )
            throws Exception
    {
        ModelAndView modelAndView = new ModelAndView ( "document" );

        WebApplicationContext context = ContextLoader.getCurrentWebApplicationContext ( );
        DocumentViewDao documentViewDao = ( DocumentViewDao ) context.getBean ( "transactionProxy" );

        Document document = DocumentViewDao.getDocument ( Integer.parseInt ( request.getParameter ( "id" ) ) );
        modelAndView.addObject ( "document", document );

        return modelAndView;
    }
}

Классы ORM и сопоставление должны быть в порядке, я не буду их писать (потерял строки :)). Так что проблема в том, что я получаю

org.hibernate.LazyInitializationException: не удалось лениво инициализировать набор ролей: orm.Document.uploadedDocumentsById, сеанс или сеанс не был закрыт

когда страница, сгенерированная контроллером.DocumentController, обновляется. Очевидно, есть проблема с кэшированием и транзакциями, которую я не могу решить. Более того, использование all() из dao.DocumentViewDao не вызывает такого исключения (но в запросе нет FETCH). Итак, у вас есть идеи? Я также буду рад любым комментариям и/или предложениям по этому коду, чтобы улучшить его (я новичок в Spring и Hibernate).


person Vasilen Donchev    schedule 09.08.2011    source источник


Ответы (1)


Когда запрос, возвращающий экземпляр(ы) объекта, может кэшироваться, и у вас есть попадание в кэш, кэш возвращает только идентификатор(ы) объекта(ов), а затем сеанс используется для загрузки объекта(ов). Это означает, что эффект объединения больше не применяется при попадании в кеш. Это также означает, что все экземпляры сущностей, возвращаемые запросом, также должны находиться в кеше второго уровня, иначе производительность может оказаться хуже, чем без кеша запросов.

Таким образом, вы должны использовать Hibernate.initialize(document.getUploadedDocumentsById() в DAO, чтобы убедиться, что он инициализирован.

person JB Nizet    schedule 09.08.2011
comment
О, это отлично работает. Но каждый раз, когда я обновляю страницу, делается запрос для извлеченного объекта... Будет хорошо, чтобы уменьшить его. - person Vasilen Donchev; 09.08.2011