mirror of https://github.com/apache/openjpa.git
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:
parent
a7cfbfc4c9
commit
944f8ad22c
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue