Skip to content

HibernateJpaDialect does not support setting a specific isolation level per transaction [SPR-5012] #9687

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 Jul 15, 2008 · 9 comments
Assignees
Labels
in: core Issues in core modules (aop, beans, core, context, expression) type: enhancement A general enhancement
Milestone

Comments

@spring-projects-issues
Copy link
Collaborator

spring-projects-issues commented Jul 15, 2008

Samuel Gaiffe opened SPR-5012 and commented

Hi,

our problem is in unit testing. When we deploy under Weblogic and use the Weblogic transaction manager, everything is ok.
But for unit testing, we use a LocalContainerEntityManagerFactoryBean with a HibernateJpaVendorAdapter injected into a JpaTransactionManager.

When isolation level other than DEFAULT is required for a transaction (setted through annotations), an InvalidIsolationLevelException is thrown.

I have solved this problem by writing a CustomHibernateJpaDialect in which I just delete the throw exception :

<i>
public class CustomHibernateJpaDialect
extends HibernateJpaDialect
{
public Object beginTransaction(EntityManager entityManager, TransactionDefinition definition)
throws PersistenceException, SQLException,
TransactionException
{
entityManager.getTransaction().begin();
return null;
}

public void cleanupTransaction(Object transactionData) {
// This line throws a NullPointerException. Got no time to go deeper but we never change the flush mode so I let it commented
//((SessionTransactionData) transactionData).resetFlushMode();
}
}
</i>

and a CustomHibernateJpaVendorAdapter in which I use my new CustomHibernateJpaDialect :

<i>
public class CustomHibernateJpaVendorAdapter extends AbstractJpaVendorAdapter
{
private final PersistenceProvider persistenceProvider = new HibernatePersistence();

private final JpaDialect jpaDialect = new CustomHibernateJpaDialect();

public PersistenceProvider getPersistenceProvider() {
return this.persistenceProvider;
}

public Map getJpaPropertyMap() {
Properties jpaProperties = new Properties();

if (getDatabasePlatform() != null) {
  jpaProperties.setProperty(Environment.DIALECT, getDatabasePlatform());
}
else if (getDatabase() != null) {
  Class databaseDialectClass = determineDatabaseDialectClass(getDatabase());
  if (databaseDialectClass != null) {
    jpaProperties.setProperty(Environment.DIALECT, databaseDialectClass.getName());
  }
}

if (isGenerateDdl()) {
  jpaProperties.setProperty(Environment.HBM2DDL_AUTO, "update");
}
if (isShowSql()) {
  jpaProperties.setProperty(Environment.SHOW_SQL, "true");
}

return jpaProperties;

}

/**

  • Determine the Hibernate database dialect class for the given target database.
  • @param database the target database
  • @return the Hibernate database dialect class, or <code>null<code> if none found
    */
    protected Class determineDatabaseDialectClass(Database database) {
    switch (database) {
    case DB2: return DB2Dialect.class;
    case HSQL: return HSQLDialect.class;
    case INFORMIX: return InformixDialect.class;
    case MYSQL: return MySQLDialect.class;
    case ORACLE: return Oracle9Dialect.class;
    case POSTGRESQL: return PostgreSQLDialect.class;
    case SQL_SERVER: return SQLServerDialect.class;
    case SYBASE: return SybaseDialect.class;
    default: return null;
    }
    }

public Class<? extends EntityManager> getEntityManagerInterface() {
return HibernateEntityManager.class;
}

public JpaDialect getJpaDialect() {
return this.jpaDialect;
}
}
</i>

I can't believe it's all we have to do to make it work correctly but I can go ahead in my unit testing.

Is my isolation level really set (I want SERIALIZABLE) ?

Thank you


Affects: 2.5.2

Issue Links:

6 votes, 11 watchers

@spring-projects-issues
Copy link
Collaborator Author

Juergen Hoeller commented

This is a known limitation: All current JPA providers make it pretty hard to set a specific isolation level for a native transaction. This is caused by the general JPA assumption that JDBC Connections will always be retrieved on demand, not necessarily held for the lifetime of a transaction... For a native transaction, the provider will have to hold a Connection per transaction eventually, but it may fetch it lazily on first access and it may release it right after transaction commit. This makes it hard to set an isolation level at the JDBC Connection level, and particularly hard to reset the original isolation level before returning the Connection to the pool!

In any case, this should be better documented. The InvalidIsolationLevelException message could be more specific as well. I'll revise the doc bits for Spring 2.5.6.

Juergen

@spring-projects-issues
Copy link
Collaborator Author

Samuel Gaiffe commented

Thank you Juergen.

I know all of this but I wanted to know if I get the desired isolation level by using this workaround or if it just bypass the isolation level setting ?

Samuel

@spring-projects-issues
Copy link
Collaborator Author

Juergen Hoeller commented

I'm afraid this workaround will just bypass the isolation level setting...

Juergen

@spring-projects-issues
Copy link
Collaborator Author

Samuel Gaiffe commented

I'll make some test to verify it and i'll let you know.

Thank you again.

Samuel

@spring-projects-issues
Copy link
Collaborator Author

Gaetan Pitteloud commented

In the case when JPA is used in local mode, which means it is configured with a DataSource, would a JpaDialect implementation that's implemented like the corresponding transaction manager do the job ?

More precisely, I use Hibernate as the JPA provider and JPA is local (not JTA); would a JPA Dialect implementation that does exactly what HibernateTransactionManager does in its doBegin(), in addition to HibernateJpaDialect, do the job ?

Thanks for the reply.

@spring-projects-issues
Copy link
Collaborator Author

Gaetan Pitteloud commented

I guess the problem comes in this call : Connection con = session.connection();
However, I suppose that with hibernate implementing local JPA, the JDBC connection returned by this call is the one used for the duration of the (local) transaction. But this is Hibernate stuff, right ?

@spring-projects-issues
Copy link
Collaborator Author

spring-projects-issues commented Sep 3, 2010

Stevo Slavić commented

Just to note, IMO this issue is related to #8492, so maybe these could be linked.

@spring-projects-issues
Copy link
Collaborator Author

Eugen Paraschiv commented

This seems to be a significant limitation with JPA, and one that could potentially be fixed at least when not using JTA transactions. Is there any way to handle that case by improving the HibernateJpaDialect?
Also, and without any concrete numbers, it seems to me that configuring Spring with JPA but not with JTA transactions is a very common use case, so handling it specifically makes a lot of sense, especially considering that the limitation is severe, and also considering that Spring with Hibernate directly should work just fine.

@spring-projects-issues
Copy link
Collaborator Author

spring-projects-issues commented Aug 9, 2014

Juergen Hoeller commented

Addressed for Hibernate EntityManager 4 in #16559.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
in: core Issues in core modules (aop, beans, core, context, expression) type: enhancement A general enhancement
Projects
None yet
Development

No branches or pull requests

2 participants