Basic knowledge about the open session in view mode

Source: Internet
Author: User


Opensessioninview
Mode usage

If the open session in view provided by spring is not used, the session must be closed at the service (or Dao) layer, So If lazy loading is set to true, link set should be initialized at the application layer, such as company. getemployees (); otherwise, Hibernate throws session already closed exception.
Open session in view provides a simple method to better solve the lazy loading problem. It has two Configuration Methods: opensessioninviewinterceptor and opensessioninviewfilter (see springside for details). The functions are the same, but one is configured in Web. XML and the other is configured in application. xml.
Open session in view keeps the hibernate session open during the request binding session to the current thread, so that the session can be used throughout the request, for example, in the view layer, PO can also lazy loading data, for example, $ {company. employees }. When the view layer logic is complete, the session will be automatically closed through the dofilter method of filter or the posthandle method of interceptor.
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>
<! -- The default value of singlesession is true. If it is set to false, opensessioninview is useless. -->
<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 mentioned an error when using opensessioninview:
Org. springframework. Dao. invaliddataaccessapiusageexception: write operations
Are not allowed in read-only mode (flushmode. Never)-Turn your session
Flushmode. Auto or remove 'readonly' marker from transaction Definition
Let's look at several methods in opensessioninviewfilter:
Protected void dofilterinternal (httpservletrequest request, httpservletresponse
Response, filterchain) throws servletexception, ioexception {
Sessionfactory = lookupsessionfactory ();
 
Logger. debug ("Opening hibernate session in opensessioninviewfilter ");
Session session =
Getsession (sessionfactory );
Transactionsynchronizationmanager. bindresource (
Sessionfactory, new sessionholder (Session ));
Try {
Filterchain. dofilter (request, response );
} Finally {

Transactionsynchronizationmanager. unbindresource (sessionfactory );
Logger. debug ("Closing hibernate
Session in opensessioninviewfilter ");
Closesession (Session, sessionfactory );
}
}

Protected session getsession (sessionfactory) throws
Dataaccessresourcefailureexception {
Session session = sessionfactoryutils. getsession (sessionfactory,
True );
Session. setflushmode (flushmode. Never );
Return session;
}

Protected void closesession (session, sessionfactory
Sessionfactory) throws cleanupfailuredataaccessexception {
Sessionfactoryutils. closesessionifnecessary (Session,
Sessionfactory );
}

We can see that opensessioninviewfilter sets the flush mode of the retrieved session to flushmode. Never when getsession. Then, bind the sessionfactory to transactionsynchronizationmanager, so that the entire request process uses the same session. After the request, the sessionfactory binding will be deleted, finally, closesessionifnecessary determines whether to close the session based on whether the session has been bound to transaction. In this process, if hibernatetemplate finds that the current session has a transaction that is not readonly, it will get flushmode. Auto session, so that the method has the write permission.

Public static void closesessionifnecessary (session, sessionfactory
Sessionfactory) throws cleanupfailuredataaccessexception {
If (session = NULL | transactionsynchronizationmanager. hasresource (sessionfactory )){
Return;
}
Logger. debug ("Closing hibernate session ");
Try {
Session. Close ();
} Catch (jdbcexception ex ){
// Sqlexception underneath
Throw new cleanupfailuredataaccessexception ("cocould
Not close hibernate session ", Ex. getsqlexception ());
} Catch (hibernateexception ex ){
Throw new
Cleanupfailuredataaccessexception ("cocould not close hibernate
Session ", ex );
}
}
That is, if there is a transaction that is not readonly, it can be flush. convert never to flush. auto has the insert, update, and delete permissions. If there is no transaction and there is no other artificially set flush model, the entire process of dofilter is flush. never. Therefore, the method protected by transaction has the write permission, but not the method protected by transaction.
Use the Spring transaction declaration to control the method by transaction.
<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>

For the preceding example, The Methods Starting with Save, add, update, and remove have writable transactions. If there is a method, for example, importexcel (), you do not have the write permission because you do not have the transaction permission. If you have insert, update, and delete operations in the method, you need to manually set the flush model to flush. auto, such:
Session. setflushmode (flushmode. Auto); Session. Save (User );
Session. Flush ();
Although the open session in view looks good, there are actually many side effects. Check the dofilterinternal method code of opensessioninviewfilter. This method is actually called by the dofilter of the parent class. Therefore, we can understand the call process of opensessioninviewfilter: request) -> open session and start transaction-> controller-> View (JSP)-> end transaction and close session.
Everything looks correct, especially when there is no problem during local development and testing, but imagine if a step in the process is blocked, in this period, the connection will remain occupied and will not be released. The most likely blocked step is to write JSP. On the one hand, it may be because the page content is large, response. Write takes a long time, and on the other hand, it may be because the network speed is slow and the transmission time between the server and the user is long. When a large number of such cases occur, there will be insufficient connection pool connections, resulting in a false page death.

[Open Session in viewIt is a double-edged sword. Please use it with caution for websites with high traffic on the public network.] 


If you have any technical questions, contact the blogger QQ: 908599713. I would like to sincerely thank every programmer ......

 

The official documentation explains the filters as follows:

 

public class OpenSessionInViewFilter
Extends onceperrequestfilter

Servlet 2.3 filter that binds a hibernate session to the thread for
Entire processing of the request. intended for the "open session in view"
Pattern, I. e. to allow for lazy loading in Web views despite the original
Transactions already being completed.

This filter makes hibernate sessions available via the current thread, which
Will be autodetected by transaction managers. It is suitable for service layer
TransactionsHibernateTransactionManager
OrJtaTransactionManager
As well as for non-transactional execution (IF configured appropriately ).

Note: This filter will by defaultNotFlush the hibernate
Session, with the flush mode setFlushMode.NEVER. It assumes
Be used in combination with service layer transactions that care for
Flushing: the active Transaction Manager will temporarily change the flush Mode
ToFlushMode.AUTODuring a read-write transaction, with the flush
Mode resetFlushMode.NEVERAt the end of each transaction. If
You intend to use this filter without transactions, consider changing
Default flush mode (through the "flushmode" property ).

Warning:Applying this filter to existing logic can cause issues that
Have not appeared before, through the use of a single hibernate session for
Processing of an entire request. In particle, the reassociation of persistent
Objects with a hibernate session has to occur at the very beginning of request
Processing, to avoid clashes with already loaded instances of the same objects.

Alternatively, turn this filter into deferred close mode, by specifying
"Singlesession" = "false": it will not use a single session per request then,
Rather let each data access operation or transaction use its own session (like
Without open session in view). Each of those sessions will be registered
Deferred close, though, actually processed at request completion.

A single session per request allows for most efficient first-level caching,
But can cause side effects, for example onsaveOrUpdateOr when
Continuing after a rolled-back transaction. The deferred close strategy is
Safe as no open session in view in that respect, while still allowing for lazy
Loading in views (but not providing a first-level cache for the entire request ).

Looks up the sessionfactory in spring's root web application context.
Supports a "sessionfactorybeanname" filter init-Param inweb.xml;
The default bean name is "sessionfactory". looks up the sessionfactory on each
Request, to avoid initialization order issues (when using contextloaderservlet,
The root application context will get initializedAfterThis filter ).

 

 

 

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.