|
#1
|
|||
|
|||
|
Hi ng,
I've been having some trouble saving objects when using the OpenSessionInViewFilter. I've tracked down the problem and it seems to be because when the session is opened in the filter it sets the flush mode to NEVER and when performing any write operation in the HibernateTempate with this flush mode a InvalidDataAccessApiUsageException is throw. How are you supposed to save using the filter? thanks, cam |
|
#2
|
|||
|
|||
|
You need to set singleSession to false. For more information, take a look at OpenSessionInViewFilter JavaDoc.
HTH |
|
#3
|
|||
|
|||
|
i looked at the javadoc before but it didn't answer my question. Why does the OpenSessionInView not allow for write operations? what was the reasoning behind this? it's been put in deliberatly and with thought, but i can't understand why it has to restrict the single session mode to read only.
cam |
|
#4
|
|||
|
|||
|
OpenSessionInViewFilter is supposed to be combined with Spring middle tier transactions. Only for a non-read-only transaction, the Session is turned to FlushMode.AUTO; it's reverted back to FlushMode.NEVER after each transaction. There is a corresponding note at the end of the javadoc.
If we wouldn't do this, OpenSessionInViewFilter's single session would not get flushed at well-controlled points in request processing. We want to avoid flushing after view rendering, as this could lead to side effects if objects get modified in the view for rendering purposes etc. With transactions, you'll also get proper rollback in case of failure: database operations will be rolled back, and the Session will be cleared. It's highly recommended to perform all data access in transactions, in particular write operations. If you absolutely want to use OpenSessionInViewFilter without middle tier transactions, follow the guideline at the end of the javadoc: override closeSession and call Session.flush() there, maybe in combination with overriding getSession and setting the Session to FlushMode.AUTO. Juergen |
|
#5
|
|||
|
|||
|
Hi Juergen,
Sorry for being away for a while but i've been distracted with different work. I understand how the OpenSessionInViewFilter works and how its ment to be used, but with further investigation i think i have tracked down the problem: The HibernateTransactionManager performs as you have desciribed and configures the flush mode for non-read-only transactions and sets it back again at the end, but we're using the JtaTransactionManager and this class does not and can not perform this kind of specific configuration. As a result the flush mode can never be set from NEVER. Here's a quote from the OpenSessionInViewFilter javadoc: Quote:
Thanks, Cam |
|
#6
|
|||
|
|||
|
Quote:
In the meantime, the quickest way to get writes working looks like this. Is there anything that we should be really concerned about with this approach? Code:
public class SessionFilter extends OpenSessionInViewFilter {
/*
* The default mode is FlushMode.NEVER
*
* @see org.springframework.orm.hibernate.support.OpenSessionInViewFilter#getSession(net.sf.hibernate.SessionFactory)
*/
protected Session getSession(SessionFactory sessionFactory)
throws DataAccessResourceFailureException {
Session session = super.getSession(sessionFactory);
session.setFlushMode(FlushMode.AUTO);
return session;
}
}
|
|
#7
|
|||
|
|||
|
In appears that setting FLUSH_AUTO in OpenSessionInViewFilter can have a drag on performance of read-only use cases. For example a big search which loads a lot of objects into the Hibernate Session will be flushed even though there is no chance of a write operation and no transaction. My timings in a profiling tool indicate the DefaultFlushEntityEventListener can take considerable time to dirty check a large session. It also creates a lot of objects for garbage collection.l
I too have the same issue with JtaTransactionManager. I would like to set FLUSH_NEVER is the view and have the existing session's flush mode bumped up automatically. My idea at this point is to extend HibernateInterceptor to change a FLUSH_NEVER session to FLUSH_AUTO and apply the interceptor to the JtaTransactionManager bean in Spring config. Anyone see problems with this approach? |
|
#8
|
|||
|
|||
|
I did some more research in this area and found that Spring works beautifully without any modification.
I used the out-of-the-box OpenSessionInViewFilter, which has FlushMode.NEVER. Whenever I need to write to the database I either (1) start a transaction using TransactionProxyFactoryBean or TransactionTemplate or (2) wrap a facade bean with HibernateInterceptor configured for FLUSH_EAGER. Using either of these methods upgrades the FlushMode on the Hibernate Session to AUTO, which is the recommended method according to Hibernate In Action. The upgrade of the flush mode seems to work fine whether the TransactionManager is JtaTransacationManager or HibernateTransactionManager. I highly recommend this approach and I have hard numbers to back it up. I compared object creation and method timing statistics for my application before and after the conversion. I found that for a single user, single read-only use case (which does a few complex searches) this approach eliminated over 2 million object creations and 30-40% time increase, all from Hibernate flusing activity. I will admit that we are flushing too often and not doing any eviction, but still this approach has to be optimal for read-only use cases. I am curious if anyone see any problems with this approach? Also, I understand why HibernateTransactionManager automatically upgrades the FlushMode on the Session, but how is this accomplished with JtaTransactionManager? Is this handled automatically somehow by Hibernate? |
|
#9
|
|||
|
|||
|
It's odd that I'm not seeing this same behavior. I'm using the default OpenSessionInViewFilter and the TransactionFactoryProxyBean which targets my dao. Invoking the save(Object obj) method on my dao causes the InvalidDataAccessApiUsageException "Write operations are not allowed in read-only mode (FlushMode.NEVER) - turn your Session into FlushMode.AUTO or remove 'readOnly' marker from transaction definition".
My transaction attributes are set as follows: Code:
<prop key="find*">PROPAGATION_REQUIRED, readOnly</prop> <prop key="load*">PROPAGATION_REQUIRED, readOnly</prop> <prop key="save*">PROPAGATION_REQUIRED</prop> ... |
|
#10
|
|||
|
|||
|
akw,
I in the same boat as you. I followed the various sample code exactly when I created my app and it worked for a while. Then I ran into this problem. Since then I've implemented most of the suggested fixes I've found in other threads and still can't get it to work. In fact, I just started a new thread on this same topic. Clearly there is something that is either very fragile or not being explained very well. |
![]() |
| Thread Tools | |
| Display Modes | |
|
|
Similar Threads
|
||||
| Thread | Thread Starter | Forum | Replies | Last Post |
| Saving Parent / Child Object Graph | matthewramella | Data Access | 3 | Nov 28th, 2007 09:33 AM |
| UpgradeAcegi Security System from 0.6.1 to 0.8.3 | mannobug | Spring Security | 3 | Sep 23rd, 2005 08:00 PM |
| saving LastLogin date | tsandor | Spring Security | 5 | Aug 23rd, 2005 08:50 PM |
| Problem saving Objects using Hibernate and PostgreSQL | gibelium | Data Access | 2 | Jul 14th, 2005 11:50 AM |
| saving data via hibernate | tuor | Data Access | 6 | Sep 13th, 2004 09:30 AM |