Non-optimistic transactions will no longer perform a version check when committing dirty objects, unless the NonOptimisticVersionCheck compatibility property is set to true. This allows dirty instances enlisted in a non-optimistic transaction to be allowed to overwrite conflicting versions in the database.

git-svn-id: https://svn.apache.org/repos/asf/incubator/openjpa/trunk@446799 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Marc Prud'hommeaux 2006-09-16 00:44:55 +00:00
parent a7cfbfc4c9
commit 944f8ad22c
6 changed files with 92 additions and 33 deletions

View File

@ -35,6 +35,7 @@ import org.apache.openjpa.kernel.OpenJPAStateManager;
import org.apache.openjpa.kernel.PCState;
import org.apache.openjpa.lib.conf.Configurable;
import org.apache.openjpa.lib.conf.Configuration;
import org.apache.openjpa.util.ImplHelper;
import org.apache.openjpa.util.OpenJPAException;
import org.apache.openjpa.util.OptimisticException;
@ -139,6 +140,8 @@ public abstract class AbstractUpdateManager
RowManager rowMgr, JDBCStore store, Collection exceps,
Collection customs) {
try {
BitSet dirty;
if (sm.getPCState() == PCState.PNEW && !sm.isFlushed()) {
insert(sm, (ClassMapping) sm.getMetaData(), rowMgr, store,
customs);
@ -146,18 +149,9 @@ public abstract class AbstractUpdateManager
|| sm.getPCState() == PCState.PDELETED) {
delete(sm, (ClassMapping) sm.getMetaData(), rowMgr, store,
customs);
} else if ((sm.getPCState() == PCState.PDIRTY && (!sm.isFlushed() || sm
.isFlushedDirty()))
|| (sm.getPCState() == PCState.PNEW && sm.isFlushedDirty())) {
BitSet dirty = sm.getDirty();
if (sm.isFlushed()) {
dirty = (BitSet) dirty.clone();
dirty.andNot(sm.getFlushed());
}
if (dirty.length() > 0)
update(sm, dirty, (ClassMapping) sm.getMetaData(), rowMgr,
store, customs);
} else if ((dirty = ImplHelper.getUpdateFields(sm)) != null) {
update(sm, dirty, (ClassMapping) sm.getMetaData(), rowMgr,
store, customs);
} else if (sm.isVersionUpdateRequired()) {
updateIndicators(sm, (ClassMapping) sm.getMetaData(), rowMgr,
store, customs, true);

View File

@ -138,7 +138,7 @@ public abstract class ColumnVersionStrategy
// set where and update conditions on row
for (int i = 0; i < cols.length; i++) {
if (curVersion != null)
if (curVersion != null && sm.isVersionCheckRequired())
row.whereObject(cols[i], curVersion);
if (vers.getColumnIO().isUpdatable(i, nextVersion == null))
row.setObject(cols[i], nextVersion);

View File

@ -101,28 +101,30 @@ public class StateComparisonVersionStrategy
// db values match our previous image
FieldMapping[] fields = (FieldMapping[]) sm.getMetaData().getFields();
Row row;
for (int i = 0, max = loaded.length(); i < max; i++) {
if (!loaded.get(i))
continue;
if (sm.isVersionCheckRequired()) {
for (int i = 0, max = loaded.length(); i < max; i++) {
if (!loaded.get(i))
continue;
// update our next state image with the new field value
if (sm.getDirty().get(i) && !sm.getFlushed().get(i))
nextState[i] = sm.fetch(fields[i].getIndex());
// update our next state image with the new field value
if (sm.getDirty().get(i) && !sm.getFlushed().get(i))
nextState[i] = sm.fetch(fields[i].getIndex());
// fetch the row for this field; if no row exists, then we can't
// add one because we have no updates to perform; that means we
// won't detect OL exceptions when another transaction changes
// fields that aren't in any of the same tables as fields that
// this transaction changed
row = rm.getRow(fields[i].getTable(), Row.ACTION_UPDATE,
sm, false);
if (row == null)
continue;
// fetch the row for this field; if no row exists, then we can't
// add one because we have no updates to perform; that means we
// won't detect OL exceptions when another transaction changes
// fields that aren't in any of the same tables as fields that
// this transaction changed
row = rm.getRow(fields[i].getTable(), Row.ACTION_UPDATE,
sm, false);
if (row == null)
continue;
// set WHERE criteria matching the previous state image so the
// update will fail if any changes have been made by another trans
fields[i].where(sm, store, rm, state[i]);
row.setFailedObject(sm.getManagedInstance());
// set WHERE criteria matching the previous state image so the
// update will fail for any changes made by another transaction
fields[i].where(sm, store, rm, state[i]);
row.setFailedObject(sm.getManagedInstance());
}
}
sm.setNextVersion(nextState);
}

View File

@ -26,6 +26,7 @@ public class Compatibility {
private boolean _copyIds = false;
private boolean _closeOnCommit = true;
private boolean _quotedNumbers = false;
private boolean _nonOptimisticVersionCheck = false;
/**
* Whether to require exact identity value types when creating object
@ -136,4 +137,24 @@ public class Compatibility {
public void setCloseOnManagedCommit(boolean close) {
_closeOnCommit = close;
}
/**
* Whether or not to perform a version check on instances being updated
* in a datastore transaction. Version of OpenJPA prior to 4.1 always
* forced a version check.
*/
public void setNonOptimisticVersionCheck
(boolean nonOptimisticVersionCheck) {
_nonOptimisticVersionCheck = nonOptimisticVersionCheck;
}
/**
* Whether or not to perform a version check on instances being updated
* in a datastore transaction. Version of OpenJPA prior to 4.1 always
* forced a version check.
*/
public boolean getNonOptimisticVersionCheck() {
return _nonOptimisticVersionCheck;
}
}

View File

@ -38,6 +38,7 @@ import org.apache.openjpa.meta.ValueMetaData;
import org.apache.openjpa.meta.ValueStrategies;
import org.apache.openjpa.util.ApplicationIds;
import org.apache.openjpa.util.Exceptions;
import org.apache.openjpa.util.ImplHelper;
import org.apache.openjpa.util.InternalException;
import org.apache.openjpa.util.InvalidStateException;
import org.apache.openjpa.util.ObjectNotFoundException;
@ -2926,7 +2927,23 @@ public class StateManagerImpl
* Returns whether this instance needs a version check.
*/
public boolean isVersionCheckRequired() {
return (_flags & FLAG_VERSION_CHECK) > 0;
// explicit flag for version check
if ((_flags & FLAG_VERSION_CHECK) > 0)
return true;
// need to check version if we have any dirty fields, unless we
// are in a datastore transaction
if (ImplHelper.getUpdateFields(this) != null) {
if (_broker.getOptimistic()) {
return true;
} else {
return _broker.getConfiguration().
getCompatibilityInstance().getNonOptimisticVersionCheck();
}
}
return false;
}
/**

View File

@ -17,6 +17,7 @@ package org.apache.openjpa.util;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.BitSet;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
@ -166,6 +167,30 @@ public class ImplHelper {
}
}
/**
* Returns the fields of the state that require an update.
*
* @param sm the state to check
* @return the BitSet of fields that need update, or null if none
*/
public static BitSet getUpdateFields(OpenJPAStateManager sm) {
if ((sm.getPCState() == PCState.PDIRTY
&& (!sm.isFlushed() || sm.isFlushedDirty()))
|| (sm.getPCState() == PCState.PNEW && sm.isFlushedDirty())) {
BitSet dirty = sm.getDirty();
if (sm.isFlushed()) {
dirty = (BitSet) dirty.clone();
dirty.andNot(sm.getFlushed());
}
if (dirty.length() > 0)
return dirty;
}
return null;
}
/**
* Close the given resource. The resource can be an extent iterator,
* query result, large result set relation, or any closeable OpenJPA