Skip to content

readOnly transaction doesn't work with JPA and Hibernate 4 [SPR-8959] #13599

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

Closed
spring-projects-issues opened this issue Dec 24, 2011 · 7 comments
Assignees
Labels
type: enhancement A general enhancement
Milestone

Comments

@spring-projects-issues
Copy link
Collaborator

spring-projects-issues commented Dec 24, 2011

Eugen Paraschiv opened SPR-8959 and commented

Setting the readOnly flag to true when Spring is configured with JPA (JpaTransactionManager, LocalContainerEntityManagerFactoryBean) with Hibernate (3.6.8) as provider works fine. When migrating to Hibernate 4 (still with the same JPA configuration) the readOnly doesn't have any effect any more. After a bit of debugging it seems that, when the underlying connection is prepared, it no longer gets marked as read only, so no exception is thrown, which means that the operation is indeed executed.
This should be easy to test, but if needed I can provide a sample project.
I will also mention that I am using MySQL.


Affects: 3.1 GA

Issue Links:

Referenced from: commits 0280a2a, 5452144, 562916b, 8a5e47a, cbda722

2 votes, 10 watchers

@spring-projects-issues
Copy link
Collaborator Author

Juergen Hoeller commented

Actually, I'm surprised that it does work for you against Hibernate 3.x: Due to limitations in JPA interaction, we don't set the read-only flag on the Connection itself when going through the JPA contract (i.e. JpaTransactionManager with HibernateJpaDialect). We rather only do that when using Hibernate natively (i.e. HibernateTransactionManager).

In general, the read-only flag is just a hint. We try to switch the flush mode to 'manual' etc, we even try to set the read-only flag on the native JDBC Connection if we can... But there are no guarantees: readOnly=true is not designed to prevent write access, it rather just gives the runtime a hint to optimize execution for read-only access.

Juergen

@spring-projects-issues
Copy link
Collaborator Author

Eugen Paraschiv commented

You are of course correct, it doesn't work for Hibernate 3.x either. I was getting another exception when writing on a read-only transaction, and I assumed it was because I was doing a write, when in fact it was something else. Sorry about the confusion, I am not able to edit the description of the issue (but it should be edited). That being said, I am aware that readOnly is just a hint and there are no guarantees, but it would be a real improvement to actually have it working with JPA and Hibernate, especially now that Spring Data JPA exists, and there is no Spring Data Hibernate.
Thanks for the response.
Eugen.

@spring-projects-issues
Copy link
Collaborator Author

KwonNam Son commented

Is there any reason not to call connection.setReadOnly() for JPA Transaction?
I use Spring 3.2, JPA 2, Hibernate 4.2 and MySQL replication driver and it requires connection.setReadOnly(true|false) for choosing write/read mysql servers.

So I made a patch for HibernateJpaDialect to call connection.setReadOnly() and it works fine till now.
I hope that I send a pull request about this patch to the springframework repository.

But If there is another reason not to call connection.setReadOnly for JPA, I have to reconsider using MySQL Replication driver.

Thanks.

@spring-projects-issues
Copy link
Collaborator Author

Juergen Hoeller commented

Calling connection.setReadOnly(true) will work fine if your connection pool happens to reset the read-only status every time a connection goes back to the pool. As with custom isolation levels on JPA, the problem is that - within the JPA resource model - we have no way to perform a custom reset of connection settings before the connection goes back to the pool. As a consequence, since we can't guarantee such a reset (and can't detect the connection pool's behavior either), we are reluctant to call setReadOnly or setIsolationLevel by default.

We could use an opt-in mode where - based on a specific deployment flag, or based on well-known connection pools - we do allow for the use of setReadOnly and setIsolationLevel. Given how popular this request is, I'm considering to revisit this for 4.1 still.

Juergen

@spring-projects-issues
Copy link
Collaborator Author

Juergen Hoeller commented

As of 4.1 RC2, HibernateJpaDialect does prepare the JDBC Connection by default if on Hibernate 4 (where the connection release mode is ON_CLOSE instead of Hibernate EntityManager 3.6's AFTER_TRANSACTION), with Hibernate 4.2+ strongly recommended (since only there the actual physical Connection is being returned to us).

Analogous to HibernateTransactionManager, there is a "prepareConnection" flag on HibernateJpaDialect which allows for overriding the actual mode of operation. This is easily accessible from HibernateJpaVendorAdapter now which declares HibernateJpaDialect from its getJpaDialect() method.

Juergen

@spring-projects-issues
Copy link
Collaborator Author

Piotr Blasiak commented

I can not see that upgrading to 4.3 does any difference when using HibernateJpaDialect. Connection.setReadOnly is never called nor do I see any calls to it in HibernateJpaDialect. Did I misunderstand the last comment, wasn´t this something that should have been implemented by now? If no, what is the recommended way to make sure connection.setReadOnly is called when using readOnly=true with spring?

@spring-projects-issues
Copy link
Collaborator Author

Piotr Blasiak commented

Never mind my last comment, it was handled in DataSourceUtils.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
type: enhancement A general enhancement
Projects
None yet
Development

No branches or pull requests

2 participants