New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Hibernate4 version of SpringSessionContext.currentSession() does not create a session if TransactionSynchronizationManager does not contain one [SPR-9020] #13659
Comments
Juergen Hoeller commented This is actually not a bug but rather a limitation that originates in Hibernate itself: The standard Hibernate CurrentSessionContext implementations only really work within active transactions. Since we're trying to do things the Hibernate way as far as possible for Hibernate 4, our SpringSessionContext delegates to Hibernate's JTASessionContext now and hence inherits its limitations. In any case, I'll have a look at what we can do about this for Spring 3.1.1. As an alternative to SUPPORTS, consider using REQUIRED in combination with readOnly=true. This is quite close in efficiency in many scenarios: There will be an active database transaction but just with read-only operations at runtime. Juergen |
Jan Bols commented Using The workaround of using |
jd commented This issue is now a real show-stopper for us as this currently leads to severe performance issues and other database bottlenecks. Due to sheer size of project changes, it is unreasonable to go back to Hibernate 3. Can we expect any solutions to this problem and SUPPORTS read-only is such a common usecase and it is an absolute show stopper for us now. Is there any alternative - however ugly - I can try to workaround this problem? |
Francois Guitton commented We have not moved to hibernate4 for the same reason. This is going to be a problem real soon as we would like to take advantage of the multi-tenancy features in h4. |
jd commented Juergen can you please elaborate on "The standard Hibernate CurrentSessionContext implementations only really work within active transactions." On looking into the org.hibernate.context.internal.ThreadLocalSessionContext.currentSession() and org.hibernate.context.internal.JTASessionContext.currentSession(), it seems like both openSession() causing a new session when no session is present. Are you referring to the fact that when a org.hibernate.internal.SessionImpl/StatelessSessionImpl gets created, a new org.hibernate.internal.TransactionCoordinatorImpl gets created whose reset() creates a new TransactionImplementor, thereby requiring a "live" transaction to be associated with a session. If sessions require a valid TransactionImplementor, what is your opinion to inject a TransactionFactory that instantiates a proxying TransactionImplementor that in turn creates a "real" transaction only when necessary? Please advice. |
Juergen Hoeller commented In standard Hibernate, JTASessionContext and ThreadLocalSessionContext do lazily create Sessions - but only within active transactions. The JTA variant will fail if no JTA transaction is active before even trying to create a Session, and the ThreadLocal variant will create a Session that is unusable before beginTransaction has been called on it. So my point basically is: The Hibernate team is quite strongly against any access to the datastore outside of a transaction. That has been the case for many years, and in more recent Hibernate versions, they are trying to enforce it rather strongly. Spring has been supporting SUPPORTS-style access to Hibernate 3 as a Spring-specific feature, and we've had several accusations of working against Hibernate's intentions there. As an important note, we've been using our own management of JTA-synchronized Hibernate 3 Sessions before which was quite involved and fragile to maintain. For our Hibernate 4 support, we are delegating to Hibernate's standard JTA synchronization now. This makes it harder to support a fallback to non-transactional Sessions since we can only do so through differentiating between JTA and non-JTA transactions in some custom way. Now, I understand that this is a common scenario. We'll see what we can do without reintroducing the deeply involved arrangement (and its problems) that we had for Hibernate 3. Juergen |
Juergen Hoeller commented A question to you guys: What kind of negative effects are you seeing when using REQUIRED instead of SUPPORTS? This should lead to a standard JDBC transaction with isolation level READ_COMMITTED, which is largely equivalent to non-transactional reading a.k.a. auto-commit reading when issuing a single SQL statement, since auto-commit operations basically use READ_COMMITTED isolation as well. The difference is just that multiple SQL statements get batched into one larger READ_COMMITTED operation instead of several. If you are seeing negative effects, I'd love to hear about your database and how it handles READ_COMMITTED. I am aware that DBMS behavior varies widely but I'm sincerely wondering about when to use SUPPORTS over REQUIRED and how database-specific any advice there is. Juergen |
Matías Mirabelli commented Hibernate does actually supports different CurrentSessionContext from outside Spring, and the session factory can be configured to use another one. There's a ManagedSessionContext that allows to bind a Session to the current thread. We've got the same issue migrating from Hibernate 3 to 4, and I found a workaround that works fine for us. I created a CurrentSessionContext that first delegates to SpringSessionContext and then it determines whether there's a Session bound to the current thread or not. If not, it means that there's no transaction in progress at all (or it was created with PROPAGATION_NEVER or PROPAGATION_SUPPORTS) so it opens a new Session and binds it to the current thread via ManagedSessionContext. In order to cleanup and close the Session at the end of the current transaction (if any), this CurrentSessionContext registers a Synchronization into TransactionSynchronizationManager, so if there's a transaction opened as PROPAGATION_NEVER or PROPAGATION_SUPPORTS the Session will be closed at the end. If there's no transaction active (which means that commit() or rollback() will never be invoked), the Session will never close. Here's the gist for this class: It can be configured in the hibernate.current_session_context_class property. Hope this help. Matías |
Burkhard Graves commented Hi, any answers to Juergens question(s)? Migrated a project to Hibernate 4 and run into this problem today, thinking about eliminating all Propagation.SUPPORTS now... Cheers |
RamCh commented Hi, We used Matias work around and working well so far. Thanks Matias. Thanks, |
Andrew Goode commented I used a slightly modified version of Matias's workaround, and it seems to work well. See his comment above and my fork of his Gist for further details. |
Fabrício Barroso de Carvalho commented The side effect caused by this approach is the overhead of creating and using a HibernateTransactionManager on simple queries. Not in resource consumption of the database, but in processing of the application server. |
thiago andrade commented For when the spring developers are scheduling to fix this bug? |
Juergen Hoeller commented Note that the effort of managing a Spring transaction scope within the application - just for the purpose of a read operation - is negligible compared to the amount of CPU cycles wasted by creating a new Hibernate Session itself... Admittedly this can become a bit more concerning with JTA in an application server environment, where the application server's JTA subsystem is also wasting some cycles on begin and commit. However, is that really significant? Have you tested that overhead or are you simply assuming that it's concerning? In addition, even our old Hibernate 3 behavior of creating a locally synchronized Session within a SUPPORTS transaction involves the management of a local transaction scope. The only difference with using REQUIRED is that the JTA subsystem and/or the underlying database resource is also being told about the transaction scope and can consider it accordingly. In a well-optimized scenario, the latter effect can be positive in terms of optimized resource management within that transaction scope. It's also still true that the Hibernate team has a very strong opinion on this: They want you to execute all Hibernate operations within a transaction, and - with every Hibernate release - make it harder and harder to achieve 100% correct behavior outside of a transaction, for both users and framework integrators. They simply don't consider that a first-class scenario and don't expose proper hooks etc (see JTASessionContext and its exception design for an example). Finally, if this is really commonly desired among Spring users even at this point, we can revisit this for Spring Framework 4.1. We definitely won't do custom JTA-based synchronization (that's pointless since the JTA synchronization facility will only work within active JTA transactions, and that's covered by Hibernate's JTASessionContext already) but can at least consider a best-effort Spring-based synchronization arrangement as a fallback if none of the regular Session retrieval strategies worked out. Juergen |
Bilal Ahmed commented Hi All, I am migrating my application from Spring 3.0.5.RELEASE to 4.3.5.Final, and Hibernate 3.6.0.Beta2 to 4.3.5.Final. Application has been working perfectly fine in older versions of Spring and Hibernate. To Juergen's point, of using "REQUIRED" instead of "SUPPORTS", Need to know, what's the fate of this bug, as it is becoming an obstacle for us at this point. Here are some details : Transactional Method Added in Service Class - From Spring Log [2014-06-25 15:00:33] [DEBUG ][org.springframework.transaction.interceptor.AbstractFallbackTransactionAttributeSource.getTransactionAttribute(AbstractFallbackTransactionAttributeSource.java:108)] "Adding transactional method 'UserServiceImpl.validateUser' with attribute: PROPAGATION_REQUIRED,ISOLATION_DEFAULT,readOnly; ''" Service Layer
} DAO Layer
} Error Caused by: org.hibernate.HibernateException: No Session found for current thread |
Luke Maurer commented It appears that programmatic demarcation using TransactionTemplate suffers from this same issue. Is it fair to say that Spring simply does not support Propagation.SUPPORTS with Hibernate 4? I fail to see what use SUPPORTS has if it doesn't bind a Hibernate session to the thread. By my understanding, if there's no transaction when a SUPPORTS method is called, the code runs non-transactionally but with a single Hibernate session used for all accesses. If SessionFactory.getCurrentSession() isn't the means to get at that single session, what is? Or, if there's no session bound to the thread at all in this case, how does |
Juergen Hoeller commented Added for 4.1 RC2 now - please give it a try in the upcoming 4.1 snapshot, or in 4.1 RC2 itself once available! We only delegate to Hibernate's JTASessionContext in case of an active JTA transaction now, manually checking the JTA status upfront. If no JTA transaction is available, we lazily create and bind a Hibernate Session to the current Spring transaction synchronization scope (for propagation SUPPORTS). Note that in contrast to our Hibernate 3 support, we don't check for any interleaving with JTA transactions here. This propagation SUPPORTS mode is only meant to work within a HibernateTransactionManager arrangement, and generally only meant to be used for transaction scopes which won't be upgraded to a full REQUIRES transaction further down the call stack. Juergen |
Reto Urfer opened SPR-9020 and commented
The Hibernate4 support of Spring 3.1 does not open and register a session in case of the method called is annotated with
@Transactional
(propagation = Propagation.SUPPORTS).In this case HibernateTransactionManager.doBegin() is never called which is the only place where hibernate session is opened. The result is, that all read operations which do not require a transaction will fail because the call to SessionFactory.currentSession() will result in an exception.
The Hibernate3 implementation contains a fallback for this case in SessionFactoryUtils.doGetSession(...) which is missing in the corresponding Hibernate4 implementation of SpringSessionContext.currentSession().
If the transaction propagation is changed to REQUIRES_NEW everything is working fine.
Affects: 3.1 GA
Issue Links:
19 votes, 28 watchers
The text was updated successfully, but these errors were encountered: