Я конвертирую старое приложение SpringMVC, которое использует Spring 2.5 для Spring 4. Я не могу заставить фильтр OpenSessionInView работать, что хорошо работает в версии 2.5.Преобразование фильтра OpenSessionInView с Spring 2.5 на Spring 4
Моя ситуация в том, что у меня есть объект команды, возвращенный в запросе GET, который затем сохраняется в сеансе. Эта форма POSTED. Некоторый код уровня обслуживания затем пытается прочитать коллекцию из объекта команды, которая не была выбрана изначально, что приводит к LazyInitializationException
.
Ошибка я получаю это:
org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: org.abc.model.Entity1.details, could not initialize proxy - no Session
web.xml:
<filter>
<filter-name>hibernateFilter</filter-name>
<filter-class>org.springframework.orm.hibernate4.support.OpenSessionInViewFilter</filter-class>
<init-param>
<param-name>sessionFactoryBeanName</param-name>
<param-value>sessionFactory</param-value>
</init-param>
</filter>
....
<filter-mapping>
<filter-name>hibernateFilter</filter-name>
<url-pattern>*.html</url-pattern>
</filter-mapping>
hibernateFilter
перечислен первым в <filter-mapping>
порядке.
В моей Hibernate.Xml я получил следующее:
<alias name="abcSessionFactory" alias="commonSessionFactory"/>
<alias name="abcSessionFactory" alias="instrSessionFactory"/>
<alias name="abcSessionFactory" alias="sessionFactory"/>
<!-- Hibernate SessionFactory -->
<bean id="abcSessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="dataSource" ref="abcDataSource"/>
<property name="mappingLocations">
<list>
<value>classpath*:/org/abc/model/*.xml</value>
<value>classpath*:/org/abc/common/model/*.xml</value>
</list>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQLInnoDBDialect</prop>
<prop key="hibernate.show_sql">false</prop>
<prop key="hibernate.cache.use_query_cache">true</prop>
<prop key="hibernate.cache.use_second_level_cache">true</prop>
<prop key="hibernate.cache.region.factory_class">org.hibernate.cache.ehcache.EhCacheRegionFactory</prop>
<prop key="hibernate.cache.provider_class">org.hibernate.cache.OSCacheProvider</prop>
</props>
</property>
</bean>
<bean id="txManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="abcSessionFactory"/>
<property name="nestedTransactionAllowed" value="true"/>
</bean>
<alias name="txManager" alias="transactionManager"/>
Я предположил бы, что там должно быть больше конфигурации, но я в недоумении.
Я пробовал использовать свойство hibernate.enable_lazy_load_no_trans
, и это действительно сработало. Но это похоже на такой общий взлом, и поэтому я действительно хотел бы выяснить, как заставить OpenSessionInViewFilter работать.
Edit:
От OpenSessionInViewFilter:
SessionFactory sessionFactory = lookupSessionFactory(request);
boolean participate = false;
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
String key = getAlreadyFilteredAttributeName();
if (TransactionSynchronizationManager.hasResource(sessionFactory)) {
// Do not modify the Session: just set the participate flag.
participate = true;
}
else {
boolean isFirstRequest = !isAsyncDispatch(request);
if (isFirstRequest || !applySessionBindingInterceptor(asyncManager, key)) {
logger.debug("Opening Hibernate Session in OpenSessionInViewFilter");
Session session = openSession(sessionFactory);
SessionHolder sessionHolder = new SessionHolder(session);
TransactionSynchronizationManager.bindResource(sessionFactory, sessionHolder);
AsyncRequestInterceptor interceptor = new AsyncRequestInterceptor(sessionFactory, sessionHolder);
asyncManager.registerCallableInterceptor(key, interceptor);
asyncManager.registerDeferredResultInterceptor(key, interceptor);
}
}
Трассировка через здесь, то session
объект создается и, кажется, хорошо.
Позже в моем коде контроллера вызывается код PersistentSet
, чтобы попытаться загрузить соответствующую коллекцию. От AbstractPersistentCollection
:
private <T> T withTemporarySessionIfNeeded(LazyInitializationWork<T> lazyInitializationWork) {
SessionImplementor originalSession = null;
boolean isTempSession = false;
boolean isJTA = false;
if (session == null) {
if (allowLoadOutsideTransaction) {
session = openTemporarySessionForLoading();
isTempSession = true;
}
else {
throwLazyInitializationException("could not initialize proxy - no Session");
}
}
else if (!session.isOpen()) {
...
...
session
имеет нулевое значение, и allowLoadOutsideTransaction
является false
. Это то, где Исключение, которое я получаю, бросается.
Я не знаю достаточно, чтобы знать, является ли session
нулевым или нет здесь, или если проблема allowOutsideTransaction
.
Хотя вы не указали способ, с которого вы начинаете транзакцию. Но если вы помечаете это на @Transactional, вам также не понадобится этот фильтр. –