--- openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/JDBCFetchConfiguration.java (revision 525577) +++ openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/JDBCFetchConfiguration.java Wed Apr 04 15:54:04 PDT 2007 @@ -16,6 +16,7 @@ package org.apache.openjpa.jdbc.kernel; import java.sql.ResultSet; +import java.sql.Connection; import java.util.Collection; import java.util.Set; @@ -169,4 +170,38 @@ * Convenience method to cast traversal to store-specific type. */ public JDBCFetchConfiguration traverseJDBC(FieldMetaData fm); + + /** + *

The isolation level for queries issued to the database. This overrides + * the persistence-unit-wide openjpa.jdbc.TransactionIsolation + * value.

+ * + *

Must be one of {@link Connection#TRANSACTION_NONE}, + * {@link Connection#TRANSACTION_READ_UNCOMMITTED}, + * {@link Connection#TRANSACTION_READ_COMMITTED}, + * {@link Connection#TRANSACTION_REPEATABLE_READ}, + * {@link Connection#TRANSACTION_SERIALIZABLE}, + * or -1 for the default connection level specified by the context in + * which this fetch configuration is being used.

+ * + * @since 0.9.7 + */ + public int getIsolationLevel(); + + /** + *

The isolation level for queries issued to the database. This overrides + * the persistence-unit-wide openjpa.jdbc.TransactionIsolation + * value.

+ * + *

Must be one of {@link Connection#TRANSACTION_NONE}, + * {@link Connection#TRANSACTION_READ_UNCOMMITTED}, + * {@link Connection#TRANSACTION_READ_COMMITTED}, + * {@link Connection#TRANSACTION_REPEATABLE_READ}, + * {@link Connection#TRANSACTION_SERIALIZABLE}, + * or -1 for the default connection level specified by the context in + * which this fetch configuration is being used.

+ * + * @since 0.9.7 + */ + public JDBCFetchConfiguration setIsolationLevel(int level); } --- openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/DelegatingJDBCFetchConfiguration.java (revision 525577) +++ openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/DelegatingJDBCFetchConfiguration.java Wed Apr 04 15:38:01 PDT 2007 @@ -240,4 +240,21 @@ throw translate(re); } } + + public int getIsolationLevel() { + try { + return getJDBCDelegate().getIsolationLevel(); + } catch (RuntimeException re) { + throw translate(re); -} + } + } + + public JDBCFetchConfiguration setIsolationLevel(int level) { + try { + getJDBCDelegate().setIsolationLevel(level); + return this; + } catch (RuntimeException re) { + throw translate(re); + } + } +} --- openjpa-jdbc/src/main/resources/org/apache/openjpa/jdbc/kernel/localizer.properties (revision 525577) +++ openjpa-jdbc/src/main/resources/org/apache/openjpa/jdbc/kernel/localizer.properties Wed Apr 04 16:03:51 PDT 2007 @@ -97,3 +97,8 @@ native-seq-usage: Usage: java org.apache.openjpa.jdbc.kernel.NativeJDBCSeq\n\ \t[-properties/-p ]\n\ \t[- ]* +bad-level: Invalid isolation level. Valid levels are -1, \ + Connection.TRANSACTION_NONE, Connection.TRANSACTION_READ_UNCOMMITTED, \ + Connection.TRANSACTION_READ_COMMITTED, \ + Connection.TRANSACTION_REPEATABLE_READ, or \ + Connection.TRANSACTION_SERIALIZABLE. Specified value: {0}. \ No newline at end of file --- openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/DB2Dictionary.java (revision 525583) +++ openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/DB2Dictionary.java Wed Apr 04 16:30:21 PDT 2007 @@ -23,8 +23,8 @@ import java.util.StringTokenizer; import org.apache.openjpa.jdbc.kernel.JDBCFetchConfiguration; import org.apache.openjpa.jdbc.schema.Sequence; -import org.apache.openjpa.lib.log.Log; import org.apache.openjpa.util.OpenJPAException; +import org.apache.openjpa.kernel.LockLevels; /** * Dictionary for IBM DB2 database. @@ -35,19 +35,20 @@ public String optimizeClause = "optimize for"; public String rowClause = "row"; private int db2ServerType = 0; - private static final int db2ISeriesV5R3AndEarlier = 1; + private static final int db2ISeriesV5R3AndEarlier = 1; private static final int db2UDBV81OrEarlier = 2; private static final int db2ZOSV8x = 3; private static final int db2UDBV82AndLater = 4; - private static final int db2ISeriesV5R4AndLater = 5; + private static final int db2ISeriesV5R4AndLater = 5; - private static final String forUpdateOfClause="FOR UPDATE OF"; + private static final String forUpdateOfClause = "FOR UPDATE OF"; - private static final String withRSClause="WITH RS"; + private static final String withRSClause = "WITH RS"; - private static final String withRRClause="WITH RR"; + private static final String withRRClause = "WITH RR"; - private static final String useKeepUpdateLockClause= "USE AND KEEP UPDATE LOCKS"; - private static final String useKeepExclusiveLockClause="USE AND KEEP EXCLUSIVE LOCKS"; + private static final String useKeepUpdateLockClause + = "USE AND KEEP UPDATE LOCKS"; + private static final String useKeepExclusiveLockClause + = "USE AND KEEP EXCLUSIVE LOCKS"; - private static final String forReadOnlyClause = "FOR READ ONLY"; + private static final String forReadOnlyClause = "FOR READ ONLY"; - public static final String UPDATE_HINT = "openjpa.hint.updateClause"; - public static final String ISOLATION_HINT = "openjpa.hint.isolationLevel"; + public DB2Dictionary() { platform = "DB2"; validationSQL = "SELECT DISTINCT(CURRENT TIMESTAMP) FROM " @@ -229,26 +230,28 @@ /** Get the update clause for the query based on the * updateClause and isolationLevel hints */ - public String getForUpdateClause(JDBCFetchConfiguration fetch, boolean forUpdate) { - String isolationLevel = null; + public String getForUpdateClause(JDBCFetchConfiguration fetch, + boolean forUpdate) { + int isolationLevel; boolean updateClause; - DatabaseMetaData metaData = null; StringBuffer forUpdateString = new StringBuffer(); try { - // Determine the update clause/isolationLevel the hint - // overrides the persistence.xml value - if (fetch != null && fetch.getHint(UPDATE_HINT) - !=null ) - updateClause = ((Boolean)fetch. - getHint(UPDATE_HINT)).booleanValue(); + // Determine the update clause/isolationLevel; the fetch + // configuration data overrides the persistence.xml value + if (fetch != null + && fetch.getReadLockLevel() == LockLevels.LOCK_WRITE) + updateClause = true; + else if (fetch != null + && fetch.getReadLockLevel() == LockLevels.LOCK_READ) + updateClause = false; - else + else updateClause = forUpdate; - if (fetch != null &&fetch.getHint(ISOLATION_HINT) - !=null ) - isolationLevel = (String)fetch. - getHint(ISOLATION_HINT); + + if (fetch != null && fetch.getIsolationLevel() != -1) + isolationLevel = fetch.getIsolationLevel(); - else + else - isolationLevel = conf.getTransactionIsolation(); + isolationLevel = conf.getTransactionIsolationConstant(); + if (updateClause == false) // This sql is not for update so add FOR Read Only clause forUpdateString.append(" ").append(forReadOnlyClause) @@ -258,36 +261,41 @@ switch(db2ServerType){ case db2ISeriesV5R3AndEarlier: case db2UDBV81OrEarlier: - if (isolationLevel.equals("read-uncommitted")) + if (isolationLevel == + Connection.TRANSACTION_READ_UNCOMMITTED) { forUpdateString.append(" ").append(withRSClause) - .append(" ").append(forUpdateOfClause).append(" "); + .append(" ").append(forUpdateOfClause).append(" "); - else + } else { forUpdateString.append(" ").append(forUpdateOfClause) - .append(" "); + .append(" "); + } - break; + break; case db2ZOSV8x: case db2UDBV82AndLater: - if (isolationLevel.equals("serializable")) + if (isolationLevel == Connection.TRANSACTION_SERIALIZABLE) { forUpdateString.append(" ").append(withRRClause) - .append(" ").append(useKeepUpdateLockClause) - .append(" "); + .append(" ").append(useKeepUpdateLockClause) + .append(" "); - else + } else { forUpdateString.append(" ").append(withRSClause) - .append(" ").append(useKeepUpdateLockClause) - .append(" "); + .append(" ").append(useKeepUpdateLockClause) + .append(" "); + } break; case db2ISeriesV5R4AndLater: - if (isolationLevel.equals("serializable")) + if (isolationLevel == Connection.TRANSACTION_SERIALIZABLE) { forUpdateString.append(" ").append(withRRClause) - .append(" ").append(useKeepExclusiveLockClause) - .append(" "); + .append(" ").append(useKeepExclusiveLockClause) + .append(" "); - else + } else { forUpdateString.append(" ").append(withRSClause) - .append(" ").append(useKeepExclusiveLockClause) - .append(" "); - } + .append(" ").append(useKeepExclusiveLockClause) + .append(" "); + } + break; - } - } + } + } + } catch (Exception e) { if (log.isTraceEnabled()) log.error(e.toString(),e); --- openjpa-persistence-jdbc/src/main/java/org/apache/openjpa/persistence/jdbc/JDBCFetchPlanImpl.java (revision 525577) +++ openjpa-persistence-jdbc/src/main/java/org/apache/openjpa/persistence/jdbc/JDBCFetchPlanImpl.java Wed Apr 04 15:36:26 PDT 2007 @@ -102,4 +102,13 @@ _fetch.setJoinSyntax(syntax); return this; } + + public int getIsolationLevel() { + return _fetch.getIsolationLevel(); -} + } + + public JDBCFetchPlan setIsolationLevel(int level) { + _fetch.setIsolationLevel(level); + return this; + } +} --- openjpa-persistence-jdbc/src/main/java/org/apache/openjpa/persistence/jdbc/JDBCFetchPlan.java (revision 525577) +++ openjpa-persistence-jdbc/src/main/java/org/apache/openjpa/persistence/jdbc/JDBCFetchPlan.java Wed Apr 04 15:54:14 PDT 2007 @@ -15,6 +15,8 @@ */ package org.apache.openjpa.persistence.jdbc; +import java.sql.Connection; + import org.apache.openjpa.jdbc.kernel.EagerFetchModes; import org.apache.openjpa.jdbc.kernel.LRSSizes; import org.apache.openjpa.jdbc.sql.JoinSyntaxes; @@ -114,4 +116,38 @@ * @see JoinSyntaxes */ public JDBCFetchPlan setJoinSyntax(int syntax); + + /** + *

The isolation level for queries issued to the database. This overrides + * the persistence-unit-wide openjpa.jdbc.TransactionIsolation + * value.

+ * + *

Must be one of {@link Connection#TRANSACTION_NONE}, + * {@link Connection#TRANSACTION_READ_UNCOMMITTED}, + * {@link Connection#TRANSACTION_READ_COMMITTED}, + * {@link Connection#TRANSACTION_REPEATABLE_READ}, + * {@link Connection#TRANSACTION_SERIALIZABLE}, + * or -1 for the default connection level specified by the context in + * which this fetch plan is being used.

+ * + * @since 0.9.7 + */ + public int getIsolationLevel(); + + /** + *

The isolation level for queries issued to the database. This overrides + * the persistence-unit-wide openjpa.jdbc.TransactionIsolation + * value.

+ * + *

Must be one of {@link Connection#TRANSACTION_NONE}, + * {@link Connection#TRANSACTION_READ_UNCOMMITTED}, + * {@link Connection#TRANSACTION_READ_COMMITTED}, + * {@link Connection#TRANSACTION_REPEATABLE_READ}, + * {@link Connection#TRANSACTION_SERIALIZABLE}, + * or -1 for the default connection level specified by the context in + * which this fetch plan is being used.

+ * + * @since 0.9.7 + */ + public JDBCFetchPlan setIsolationLevel(int level); } --- openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/JDBCFetchConfigurationImpl.java (revision 525577) +++ openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/JDBCFetchConfigurationImpl.java Wed Apr 04 15:56:56 PDT 2007 @@ -17,6 +17,7 @@ import java.io.Serializable; import java.sql.ResultSet; +import java.sql.Connection; import java.util.Collection; import java.util.Collections; import java.util.HashSet; @@ -65,6 +66,7 @@ public int size = 0; public int syntax = 0; public Set joins = null; + public int isolationLevel = -1; } private final JDBCConfigurationState _state; @@ -319,4 +321,22 @@ return null; return (JDBCConfiguration) conf; } + + public int getIsolationLevel() { + return _state.isolationLevel; -} + } + + public JDBCFetchConfiguration setIsolationLevel(int level) { + if (level != -1 + && level != Connection.TRANSACTION_NONE + && level != Connection.TRANSACTION_READ_UNCOMMITTED + && level != Connection.TRANSACTION_READ_COMMITTED + && level != Connection.TRANSACTION_REPEATABLE_READ + && level != Connection.TRANSACTION_SERIALIZABLE) + throw new IllegalArgumentException( + _loc.get("bad-level", Integer.valueOf(level)).getMessage()); + + _state.isolationLevel = level; + return this; + } +}