If the session is closed in the service (or Dao) layer without using the open session in view provided by spring, the lazy loading is true if the relationship set is initialized within the application layer, as Company.getemployees (), otherwise hibernate throw session already closed Exception; Open Session in view provides a convenient way to solve the problem of lazy loading.
It has two configurations, Opensessioninviewinterceptor and Opensessioninviewfilter (see Springside), with the same functionality, Just one in the Web. XML configuration, the other in Application.xml configuration only.
Open session in view keeps hibernate session open during request binding session to the current thread, so that the session can be used throughout the request. As in the view Layer PO can also be lazy loading data, such as ${company.employees}. When the view layer logic is complete, the session is automatically closed via the filter's Dofilter method or Interceptor's Posthandle method.
Opensessioninviewinterceptor configuration <beans> <bean name= "Opensessioninviewinterceptor"class= "Org.springframework.orm.hibernate3.support.OpenSessionInViewInterceptor" > <property name= "sessionfactory "> <ref bean=" sessionfactory "/> </property> </bean> <bean id=" UrlMapping "class= "Org.springframework.web.servlet.handler.SimpleUrlHandlerMapping" > <property name= "Interceptors" > < list> <ref bean= "Opensessioninviewinterceptor"/> </list> </property> <property name= " Mappings "> ... </property> </bean> ... </beans> opensessioninviewfilter configuration <web-app> ... < filter> <filter-name>hibernateFilter</filter-name> <filter-class> org. springframework. Orm. Hibernate3. Support. Opensessioninviewfilter </filter-class> <!--singlesession The default is true, and if set to false is useless opensessioninview-- <init-param> <param-name>singleSession</param-name> <param-value>true</param-value > </init-param> </filter> ... <filter-mapping> <filter-name>hibernatefilter</ Filter-name> <url-pattern>*. Do</url-pattern> </filter-mapping> ... </web-app>
Many people use the Opensessioninview process to mention an error: Org. springframework. Dao. Invaliddataaccessapiusageexception:write operations is not allowed in read-only mode (Flushmode. Never)-turn your Session into Flushmode. AUTO or remove ' readOnly ' marker from transaction definition
Look at some of the ways in Opensessioninviewfilter.protectedvoid Dofilterinternal (HttpServletRequest request,
HttpServletResponse Response,filterchain Filterchain)
throwsServletexception, IOException {
Sessionfactory sessionfactory = Lookupsessionfactory ();
Logger. Debug ("Opening Hibernate Session in Opensessioninviewfilter");
Session session = GetSession (sessionfactory);
Transactionsynchronizationmanager. Bindresource (
Sessionfactory,NewSessionholder (session));
Try{
Filterchain. DoFilter (request, response);
}
finally{
Transactionsynchronizationmanager. Unbindresource (sessionfactory);
Logger. Debug ("Closing Hibernate Session in Opensessioninviewfilter");
CloseSession (session, Sessionfactory);
}
}
protectedSession getsession (sessionfactory sessionfactory)
throwsdataaccessresourcefailureexception {
Session session = Sessionfactoryutils. GetSession (Sessionfactory,true);
Session. Setflushmode (Flushmode. Never);
returnSession
}
protectedvoid CloseSession (Session session, Sessionfactory Sessionfactory)
throwscleanupfailuredataaccessexception {
Sessionfactoryutils.closesessionifnecessary (session, Sessionfactory);
}
Can see Opensessioninviewfilter in GetSession, will get back to the session of the flush mode set to Flushmode.never. The sessionfactory is then bound to the Transactionsynchronizationmanager so that the entire request process uses the same session, after which the binding of the sessionfactory is removed, Finally closesessionifnecessary determines whether the session is closed based on whether the session has been bound to the transaction. In this process, if hibernatetemplate found from the current session is not READONLY transaction, will get to the Flushmode.auto Session, so that the method has write permissions. Public Staticvoid Closesessionifnecessary (Session session, Sessionfactory Sessionfactory)throwsCleanupfailuredataaccessexception {if (session = =NULL||
Transactionsynchronizationmanager. Hasresource (sessionfactory)) {return; } logger. Debug ("Closing Hibernate session");Try{session. Close ();}Catch(Jdbcexception ex) {//SQLException underneathThrow NewCleanupfailuredataaccessexception ("Could not close Hibernate session", ex. getsqlexception ()); }Catch(Hibernateexception ex) {Throw NewCleanupfailuredataaccessexception ("Could not close Hibernate session", ex); } }
That is, if there is not ReadOnly transaction can be converted from flush.never to Flush.auto, with insert,update,delete operation Rights, if there is no transaction, And without the flush model being artificially set, the whole process of dofilter is flush.never. So the method protected by transaction has write permission, not protected. Use spring's transaction declaration to make the method subject to transaction control <bean id= "Basetransaction"
Class= "Org.springframework.transaction.interceptor.TransactionProxyFactoryBean"
Abstract= "true" >
<property name= "TransactionManager" ref= "TransactionManager"/>
<property name= "Proxytargetclass" value= "true"/>
<property name= "Transactionattributes" >
<props>
<prop key= "get*" >PROPAGATION_REQUIRED,readOnly</prop>
<prop key= "find*" >PROPAGATION_REQUIRED,readOnly</prop>
<prop key= "load*" >PROPAGATION_REQUIRED,readOnly</prop>
<prop key= "save*" >PROPAGATION_REQUIRED</prop>
<prop key= "add*" >PROPAGATION_REQUIRED</prop>
<prop key= "update*" >PROPAGATION_REQUIRED</prop>
<prop key= "remove*" >PROPAGATION_REQUIRED</prop>
</props>
</property>
</bean>
<bean id= "UserService" parent= "Basetransaction" >
<property name= "Target" >
<bean class= "Com.phopesoft.security.service.impl.UserServiceImpl"/>
</property>
</bean>
For the above example, the method beginning with Save,add,update,remove has a writable transaction, if there is a method, such as named Importexcel (), because there is no transaction and no write permission, then if there is insert inside the method, Update,delete operation, you need to manually set the flush model to Flush.auto, such as session. Setflushmode (Flushmode. AUTO); Session. Save (user); Session. Flush ();
Although the open Session in view looks good, there are many side effects. Looking back at the Opensessioninviewfilter Dofilterinternal method code above, this method is actually called by the Dofilter of the parent class, so We can learn about the Opensessioninviewfilter invocation process: request (requests)->open session and start Transaction->controller->view (JSP)- > End transaction and close session.
Everything seems to be right, especially if there is no problem at the time of the local development test, but imagine if a step in the process is blocked, then the connection is occupied and not released. The most likely to be blocked is to write JSP this step, on the one hand may be the page content is large, Response.Write time is long, on the other hand may be slow, the server and the user between the transmission time long. When a large number of such cases occur, there is insufficient connection pool connection, causing the page suspended animation phenomenon.
Open Session In view is a double-edged sword, on the public web content of large-volume website please use with caution