diff --git a/spring-orm/src/main/java/org/springframework/orm/jdo/DefaultJdoDialect.java b/spring-orm/src/main/java/org/springframework/orm/jdo/DefaultJdoDialect.java index 38d0f7263a..9d058158b9 100644 --- a/spring-orm/src/main/java/org/springframework/orm/jdo/DefaultJdoDialect.java +++ b/spring-orm/src/main/java/org/springframework/orm/jdo/DefaultJdoDialect.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2012 the original author or authors. + * Copyright 2002-2013 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,6 +19,7 @@ package org.springframework.orm.jdo; import java.lang.reflect.Method; import java.sql.Connection; import java.sql.SQLException; +import javax.jdo.Constants; import javax.jdo.JDOException; import javax.jdo.PersistenceManager; import javax.jdo.Query; @@ -32,7 +33,6 @@ import org.springframework.dao.support.PersistenceExceptionTranslator; import org.springframework.jdbc.datasource.ConnectionHandle; import org.springframework.jdbc.support.JdbcUtils; import org.springframework.jdbc.support.SQLExceptionTranslator; -import org.springframework.transaction.InvalidIsolationLevelException; import org.springframework.transaction.TransactionDefinition; import org.springframework.transaction.TransactionException; import org.springframework.util.ClassUtils; @@ -40,13 +40,13 @@ import org.springframework.util.ReflectionUtils; /** * Default implementation of the {@link JdoDialect} interface. - * Updated to build on JDO 2.0 or higher, as of Spring 2.5. + * Requires JDO 2.0; explicitly supports JDO API features up until 3.0. * Used as default dialect by {@link JdoAccessor} and {@link JdoTransactionManager}. * *
Simply begins a standard JDO transaction in {@code beginTransaction}. * Returns a handle for a JDO2 DataStoreConnection on {@code getJdbcConnection}. * Calls the corresponding JDO2 PersistenceManager operation on {@code flush} - * Ignores a given query timeout in {@code applyQueryTimeout}. + * Translates {@code applyQueryTimeout} to JDO 3.0's {@code setTimeoutMillis}. * Uses a Spring SQLExceptionTranslator for exception translation, if applicable. * *
Note that, even with JDO2, vendor-specific subclasses are still necessary @@ -122,24 +122,49 @@ public class DefaultJdoDialect implements JdoDialect, PersistenceExceptionTransl //------------------------------------------------------------------------- /** - * This implementation invokes the standard JDO {@code Transaction.begin} - * method. Throws an InvalidIsolationLevelException if a non-default isolation - * level is set. + * This implementation invokes the standard JDO {@link Transaction#begin()} + * method and also {@link Transaction#setIsolationLevel(String)} if necessary. * @see javax.jdo.Transaction#begin * @see org.springframework.transaction.InvalidIsolationLevelException */ public Object beginTransaction(Transaction transaction, TransactionDefinition definition) throws JDOException, SQLException, TransactionException { - if (definition.getIsolationLevel() != TransactionDefinition.ISOLATION_DEFAULT) { - throw new InvalidIsolationLevelException( - "Standard JDO does not support custom isolation levels: " + - "use a special JdoDialect implementation for your JDO provider"); + String jdoIsolationLevel = getJdoIsolationLevel(definition); + if (jdoIsolationLevel != null) { + transaction.setIsolationLevel(jdoIsolationLevel); } transaction.begin(); return null; } + /** + * Determine the JDO isolation level String to use for the given + * Spring transaction definition. + * @param definition the Spring transaction definition + * @return the corresponding JDO isolation level String, or {@code null} + * to indicate that no isolation level should be set explicitly + * @see Transaction#setIsolationLevel(String) + * @see Constants#TX_SERIALIZABLE + * @see Constants#TX_REPEATABLE_READ + * @see Constants#TX_READ_COMMITTED + * @see Constants#TX_READ_UNCOMMITTED + */ + protected String getJdoIsolationLevel(TransactionDefinition definition) { + switch (definition.getIsolationLevel()) { + case TransactionDefinition.ISOLATION_SERIALIZABLE: + return Constants.TX_SERIALIZABLE; + case TransactionDefinition.ISOLATION_REPEATABLE_READ: + return Constants.TX_REPEATABLE_READ; + case TransactionDefinition.ISOLATION_READ_COMMITTED: + return Constants.TX_READ_COMMITTED; + case TransactionDefinition.ISOLATION_READ_UNCOMMITTED: + return Constants.TX_READ_UNCOMMITTED; + default: + return null; + } + } + /** * This implementation does nothing, as the default beginTransaction implementation * does not require any cleanup. diff --git a/spring-orm/src/test/java/org/springframework/orm/jdo/JdoTransactionManagerTests.java b/spring-orm/src/test/java/org/springframework/orm/jdo/JdoTransactionManagerTests.java index 538ce2572b..46003776b0 100644 --- a/spring-orm/src/test/java/org/springframework/orm/jdo/JdoTransactionManagerTests.java +++ b/spring-orm/src/test/java/org/springframework/orm/jdo/JdoTransactionManagerTests.java @@ -16,17 +16,6 @@ package org.springframework.orm.jdo; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertSame; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; -import static org.mockito.BDDMockito.given; -import static org.mockito.BDDMockito.willThrow; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; - import java.lang.reflect.Proxy; import java.sql.Connection; import java.sql.DatabaseMetaData; @@ -34,7 +23,7 @@ import java.sql.SQLException; import java.sql.Savepoint; import java.util.ArrayList; import java.util.List; - +import javax.jdo.Constants; import javax.jdo.JDOFatalDataStoreException; import javax.jdo.PersistenceManager; import javax.jdo.PersistenceManagerFactory; @@ -48,6 +37,7 @@ import javax.transaction.UserTransaction; import org.junit.After; import org.junit.Before; import org.junit.Test; + import org.springframework.jdbc.datasource.ConnectionHandle; import org.springframework.jdbc.datasource.ConnectionHolder; import org.springframework.jdbc.datasource.SimpleConnectionHandle; @@ -55,7 +45,6 @@ import org.springframework.orm.jdo.support.SpringPersistenceManagerProxyBean; import org.springframework.orm.jdo.support.StandardPersistenceManagerProxyBean; import org.springframework.tests.sample.beans.TestBean; import org.springframework.tests.transaction.MockJtaTransaction; -import org.springframework.transaction.InvalidIsolationLevelException; import org.springframework.transaction.PlatformTransactionManager; import org.springframework.transaction.TransactionDefinition; import org.springframework.transaction.TransactionStatus; @@ -65,6 +54,12 @@ import org.springframework.transaction.support.TransactionCallbackWithoutResult; import org.springframework.transaction.support.TransactionSynchronizationManager; import org.springframework.transaction.support.TransactionTemplate; +import static org.junit.Assert.*; +import static org.mockito.BDDMockito.*; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; + /** * @author Juergen Hoeller * @author Phillip Webb @@ -620,24 +615,19 @@ public class JdoTransactionManagerTests { } @Test - public void testInvalidIsolation() { + public void testIsolationLevel() { given(pmf.getPersistenceManager()).willReturn(pm); given(pm.currentTransaction()).willReturn(tx); PlatformTransactionManager tm = new JdoTransactionManager(pmf); TransactionTemplate tt = new TransactionTemplate(tm); tt.setIsolationLevel(TransactionDefinition.ISOLATION_SERIALIZABLE); - try { - tt.execute(new TransactionCallbackWithoutResult() { - @Override - protected void doInTransactionWithoutResult(TransactionStatus status) { - } - }); - fail("Should have thrown InvalidIsolationLevelException"); - } - catch (InvalidIsolationLevelException ex) { - // expected - } + tt.execute(new TransactionCallbackWithoutResult() { + @Override + protected void doInTransactionWithoutResult(TransactionStatus status) { + } + }); + verify(tx).setIsolationLevel(Constants.TX_SERIALIZABLE); verify(pm).close(); }