HHH-4546 - add JPA 2.0 locking
git-svn-id: https://svn.jboss.org/repos/hibernate/core/trunk@17944 1b8cb986-b30d-0410-93ca-fae66ebed9b2
This commit is contained in:
parent
1bd95b3c1c
commit
d82c1e859b
|
@ -87,6 +87,7 @@ public final class LockMode implements Serializable {
|
||||||
/**
|
/**
|
||||||
* An upgrade lock. Objects loaded in this lock mode are
|
* An upgrade lock. Objects loaded in this lock mode are
|
||||||
* materialized using an SQL <tt>select ... for update</tt>.
|
* materialized using an SQL <tt>select ... for update</tt>.
|
||||||
|
* @deprecated instead use PESSIMISTIC_WRITE
|
||||||
*/
|
*/
|
||||||
public static final LockMode UPGRADE = new LockMode(10, "UPGRADE");
|
public static final LockMode UPGRADE = new LockMode(10, "UPGRADE");
|
||||||
/**
|
/**
|
||||||
|
@ -107,9 +108,47 @@ public final class LockMode implements Serializable {
|
||||||
/**
|
/**
|
||||||
* Similiar to {@link #UPGRADE} except that, for versioned entities,
|
* Similiar to {@link #UPGRADE} except that, for versioned entities,
|
||||||
* it results in a forced version increment.
|
* it results in a forced version increment.
|
||||||
|
* @deprecated instead use PESSIMISTIC_FORCE_INCREMENT
|
||||||
*/
|
*/
|
||||||
public static final LockMode FORCE = new LockMode( 15, "FORCE" );
|
public static final LockMode FORCE = new LockMode( 15, "FORCE" );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* start of javax.persistence.LockModeType equivalent modes
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Optimisticly assume that transaction will not experience contention for
|
||||||
|
* entities. The entity version will be verified near the transaction end.
|
||||||
|
*/
|
||||||
|
public static final LockMode OPTIMISTIC = new LockMode(3,"OPTIMISTIC");
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Optimisticly assume that transaction will not experience contention for entities.
|
||||||
|
* The entity version will be verified and incremented near the transaction end.
|
||||||
|
*/
|
||||||
|
public static final LockMode OPTIMISTIC_FORCE_INCREMENT = new LockMode(7,"OPTIMISTIC_FORCE_INCREMENT");
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implemented as PESSIMISTIC_WRITE.
|
||||||
|
* TODO: introduce separate support for PESSIMISTIC_READ
|
||||||
|
*/
|
||||||
|
public static final LockMode PESSIMISTIC_READ = new LockMode(12,"PESSIMISTIC_READ");
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Transaction will obtain a database lock immediately.
|
||||||
|
* TODO: add PESSIMISTIC_WRITE_NOWAIT
|
||||||
|
*/
|
||||||
|
public static final LockMode PESSIMISTIC_WRITE = new LockMode(13,"PESSIMISTIC_WRITE");
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Transaction will immediately increment the entity version.
|
||||||
|
*/
|
||||||
|
public static final LockMode PESSIMISTIC_FORCE_INCREMENT = new LockMode(17,"PESSIMISTIC_FORCE_INCREMENT");
|
||||||
|
|
||||||
|
/**
|
||||||
|
* end of javax.persistence.LockModeType modes
|
||||||
|
*/
|
||||||
|
|
||||||
static {
|
static {
|
||||||
INSTANCES.put( NONE.name, NONE );
|
INSTANCES.put( NONE.name, NONE );
|
||||||
INSTANCES.put( READ.name, READ );
|
INSTANCES.put( READ.name, READ );
|
||||||
|
@ -117,6 +156,11 @@ public final class LockMode implements Serializable {
|
||||||
INSTANCES.put( UPGRADE_NOWAIT.name, UPGRADE_NOWAIT );
|
INSTANCES.put( UPGRADE_NOWAIT.name, UPGRADE_NOWAIT );
|
||||||
INSTANCES.put( WRITE.name, WRITE );
|
INSTANCES.put( WRITE.name, WRITE );
|
||||||
INSTANCES.put( FORCE.name, FORCE );
|
INSTANCES.put( FORCE.name, FORCE );
|
||||||
|
INSTANCES.put( OPTIMISTIC.name, OPTIMISTIC);
|
||||||
|
INSTANCES.put( OPTIMISTIC_FORCE_INCREMENT.name, OPTIMISTIC_FORCE_INCREMENT);
|
||||||
|
INSTANCES.put( PESSIMISTIC_READ. name, PESSIMISTIC_READ);
|
||||||
|
INSTANCES.put( PESSIMISTIC_WRITE.name, PESSIMISTIC_WRITE);
|
||||||
|
INSTANCES.put( PESSIMISTIC_FORCE_INCREMENT.name, PESSIMISTIC_FORCE_INCREMENT);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Object readResolve() {
|
private Object readResolve() {
|
||||||
|
|
|
@ -0,0 +1,51 @@
|
||||||
|
/*
|
||||||
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
|
*
|
||||||
|
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
|
||||||
|
* indicated by the @author tags or express copyright attribution
|
||||||
|
* statements applied by the authors. All third-party contributions are
|
||||||
|
* distributed under license by Red Hat Middleware LLC.
|
||||||
|
*
|
||||||
|
* This copyrighted material is made available to anyone wishing to use, modify,
|
||||||
|
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||||
|
* Lesser General Public License, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||||
|
* for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with this distribution; if not, write to:
|
||||||
|
* Free Software Foundation, Inc.
|
||||||
|
* 51 Franklin Street, Fifth Floor
|
||||||
|
* Boston, MA 02110-1301 USA
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
package org.hibernate;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* Throw when an optimistic locking conflict occurs.
|
||||||
|
*
|
||||||
|
* @author Scott Marlow
|
||||||
|
*/
|
||||||
|
public class OptimisticLockException extends HibernateException {
|
||||||
|
|
||||||
|
Object entity;
|
||||||
|
|
||||||
|
public OptimisticLockException(String s) {
|
||||||
|
super(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
public OptimisticLockException(String s, Object entity) {
|
||||||
|
super(s);
|
||||||
|
this.entity = entity;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Object getEntity() {
|
||||||
|
return entity;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,50 @@
|
||||||
|
/*
|
||||||
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
|
*
|
||||||
|
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
|
||||||
|
* indicated by the @author tags or express copyright attribution
|
||||||
|
* statements applied by the authors. All third-party contributions are
|
||||||
|
* distributed under license by Red Hat Middleware LLC.
|
||||||
|
*
|
||||||
|
* This copyrighted material is made available to anyone wishing to use, modify,
|
||||||
|
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||||
|
* Lesser General Public License, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||||
|
* for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with this distribution; if not, write to:
|
||||||
|
* Free Software Foundation, Inc.
|
||||||
|
* 51 Franklin Street, Fifth Floor
|
||||||
|
* Boston, MA 02110-1301 USA
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
package org.hibernate;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* Throw when an pessimistic locking conflict occurs.
|
||||||
|
*
|
||||||
|
* @author Scott Marlow
|
||||||
|
*/
|
||||||
|
public class PessimisticLockException extends HibernateException {
|
||||||
|
|
||||||
|
Object entity;
|
||||||
|
|
||||||
|
public PessimisticLockException(String s) {
|
||||||
|
super(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
public PessimisticLockException(String s, Object entity) {
|
||||||
|
super(s);
|
||||||
|
this.entity = entity;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Object getEntity() {
|
||||||
|
return entity;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,58 @@
|
||||||
|
/*
|
||||||
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
|
*
|
||||||
|
* Copyright (c) 2009, Red Hat Middleware LLC or third-party contributors as
|
||||||
|
* indicated by the @author tags or express copyright attribution
|
||||||
|
* statements applied by the authors. All third-party contributions are
|
||||||
|
* distributed under license by Red Hat Middleware LLC.
|
||||||
|
*
|
||||||
|
* This copyrighted material is made available to anyone wishing to use, modify,
|
||||||
|
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||||
|
* Lesser General Public License, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||||
|
* for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with this distribution; if not, write to:
|
||||||
|
* Free Software Foundation, Inc.
|
||||||
|
* 51 Franklin Street, Fifth Floor
|
||||||
|
* Boston, MA 02110-1301 USA
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
package org.hibernate.action;
|
||||||
|
|
||||||
|
import org.hibernate.engine.SessionImplementor;
|
||||||
|
import org.hibernate.engine.EntityEntry;
|
||||||
|
import org.hibernate.persister.entity.EntityPersister;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Verify/Increment the entity version
|
||||||
|
*
|
||||||
|
* @author Scott Marlow
|
||||||
|
*/
|
||||||
|
public class EntityIncrementVersionProcess implements BeforeTransactionCompletionProcess
|
||||||
|
{
|
||||||
|
private final Object object;
|
||||||
|
private final EntityEntry entry;
|
||||||
|
|
||||||
|
public EntityIncrementVersionProcess(Object object, EntityEntry entry) {
|
||||||
|
this.object = object;
|
||||||
|
this.entry = entry;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Perform whatever processing is encapsulated here before completion of the transaction.
|
||||||
|
*
|
||||||
|
* @param session The session on which the transaction is preparing to complete.
|
||||||
|
*/
|
||||||
|
public void doBeforeTransactionCompletion(SessionImplementor session) {
|
||||||
|
final EntityPersister persister = entry.getPersister();
|
||||||
|
Object nextVersion = persister.forceVersionIncrement(
|
||||||
|
entry.getId(), entry.getVersion(), session
|
||||||
|
);
|
||||||
|
entry.forceLocked( object, nextVersion );
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,64 @@
|
||||||
|
/*
|
||||||
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
|
*
|
||||||
|
* Copyright (c) 2009, Red Hat Middleware LLC or third-party contributors as
|
||||||
|
* indicated by the @author tags or express copyright attribution
|
||||||
|
* statements applied by the authors. All third-party contributions are
|
||||||
|
* distributed under license by Red Hat Middleware LLC.
|
||||||
|
*
|
||||||
|
* This copyrighted material is made available to anyone wishing to use, modify,
|
||||||
|
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||||
|
* Lesser General Public License, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||||
|
* for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with this distribution; if not, write to:
|
||||||
|
* Free Software Foundation, Inc.
|
||||||
|
* 51 Franklin Street, Fifth Floor
|
||||||
|
* Boston, MA 02110-1301 USA
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
package org.hibernate.action;
|
||||||
|
|
||||||
|
import org.hibernate.engine.SessionImplementor;
|
||||||
|
import org.hibernate.engine.EntityEntry;
|
||||||
|
import org.hibernate.persister.entity.EntityPersister;
|
||||||
|
import org.hibernate.HibernateException;
|
||||||
|
import org.hibernate.OptimisticLockException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Verify/Increment the entity version
|
||||||
|
*
|
||||||
|
* @author Scott Marlow
|
||||||
|
*/
|
||||||
|
public class EntityVerifyVersionProcess implements BeforeTransactionCompletionProcess
|
||||||
|
{
|
||||||
|
private final Object object;
|
||||||
|
private final EntityEntry entry;
|
||||||
|
|
||||||
|
public EntityVerifyVersionProcess(Object object, EntityEntry entry) {
|
||||||
|
this.object = object;
|
||||||
|
this.entry = entry;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Perform whatever processing is encapsulated here before completion of the transaction.
|
||||||
|
*
|
||||||
|
* @param session The session on which the transaction is preparing to complete.
|
||||||
|
*/
|
||||||
|
public void doBeforeTransactionCompletion(SessionImplementor session) {
|
||||||
|
final EntityPersister persister = entry.getPersister();
|
||||||
|
|
||||||
|
Object latestVersion = persister.getCurrentVersion(
|
||||||
|
entry.getId(), session
|
||||||
|
);
|
||||||
|
if(!entry.getVersion().equals(latestVersion))
|
||||||
|
throw new OptimisticLockException(
|
||||||
|
"Newer version ("+ latestVersion+
|
||||||
|
") of entity ("+entry.getEntityName()+") found in database. id=" + entry.getId());
|
||||||
|
}
|
||||||
|
}
|
|
@ -382,6 +382,21 @@ public abstract class ResultSetMappingBinder {
|
||||||
else if ( "force".equals( lockMode ) ) {
|
else if ( "force".equals( lockMode ) ) {
|
||||||
return LockMode.FORCE;
|
return LockMode.FORCE;
|
||||||
}
|
}
|
||||||
|
else if ( "optimistic".equals( lockMode ) ) {
|
||||||
|
return LockMode.OPTIMISTIC;
|
||||||
|
}
|
||||||
|
else if ( "optimistic_force_increment".equals( lockMode ) ) {
|
||||||
|
return LockMode.OPTIMISTIC_FORCE_INCREMENT;
|
||||||
|
}
|
||||||
|
else if ( "pessimistic_read".equals( lockMode ) ) {
|
||||||
|
return LockMode.PESSIMISTIC_READ;
|
||||||
|
}
|
||||||
|
else if ( "pessimistic_write".equals( lockMode ) ) {
|
||||||
|
return LockMode.PESSIMISTIC_WRITE;
|
||||||
|
}
|
||||||
|
else if ( "pessimistic_force_increment".equals( lockMode ) ) {
|
||||||
|
return LockMode.PESSIMISTIC_FORCE_INCREMENT;
|
||||||
|
}
|
||||||
else {
|
else {
|
||||||
throw new MappingException( "unknown lockmode" );
|
throw new MappingException( "unknown lockmode" );
|
||||||
}
|
}
|
||||||
|
|
|
@ -962,13 +962,13 @@ public abstract class Dialect {
|
||||||
* @return The appropriate for update fragment.
|
* @return The appropriate for update fragment.
|
||||||
*/
|
*/
|
||||||
public String getForUpdateString(LockMode lockMode) {
|
public String getForUpdateString(LockMode lockMode) {
|
||||||
if ( lockMode==LockMode.UPGRADE ) {
|
if ( lockMode==LockMode.UPGRADE || lockMode==LockMode.PESSIMISTIC_READ || lockMode==LockMode.PESSIMISTIC_WRITE) {
|
||||||
return getForUpdateString();
|
return getForUpdateString();
|
||||||
}
|
}
|
||||||
else if ( lockMode==LockMode.UPGRADE_NOWAIT ) {
|
else if ( lockMode==LockMode.UPGRADE_NOWAIT ) {
|
||||||
return getForUpdateNowaitString();
|
return getForUpdateNowaitString();
|
||||||
}
|
}
|
||||||
else if ( lockMode==LockMode.FORCE ) {
|
else if ( lockMode==LockMode.FORCE || lockMode==LockMode.PESSIMISTIC_FORCE_INCREMENT) {
|
||||||
return getForUpdateNowaitString();
|
return getForUpdateNowaitString();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
|
|
@ -252,7 +252,7 @@ public final class EntityEntry implements Serializable {
|
||||||
public void forceLocked(Object entity, Object nextVersion) {
|
public void forceLocked(Object entity, Object nextVersion) {
|
||||||
version = nextVersion;
|
version = nextVersion;
|
||||||
loadedState[ persister.getVersionProperty() ] = version;
|
loadedState[ persister.getVersionProperty() ] = version;
|
||||||
setLockMode( LockMode.FORCE );
|
setLockMode( LockMode.FORCE ); // TODO: use LockMode.PESSIMISTIC_FORCE_INCREMENT
|
||||||
persister.setPropertyValue(
|
persister.setPropertyValue(
|
||||||
entity,
|
entity,
|
||||||
getPersister().getVersionProperty(),
|
getPersister().getVersionProperty(),
|
||||||
|
|
|
@ -29,11 +29,14 @@ import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import org.hibernate.LockMode;
|
import org.hibernate.LockMode;
|
||||||
import org.hibernate.ObjectDeletedException;
|
import org.hibernate.ObjectDeletedException;
|
||||||
|
import org.hibernate.OptimisticLockException;
|
||||||
|
import org.hibernate.event.EventSource;
|
||||||
|
import org.hibernate.action.EntityIncrementVersionProcess;
|
||||||
|
import org.hibernate.action.EntityVerifyVersionProcess;
|
||||||
import org.hibernate.cache.CacheKey;
|
import org.hibernate.cache.CacheKey;
|
||||||
import org.hibernate.cache.access.SoftLock;
|
import org.hibernate.cache.access.SoftLock;
|
||||||
import org.hibernate.engine.EntityEntry;
|
import org.hibernate.engine.EntityEntry;
|
||||||
import org.hibernate.engine.Status;
|
import org.hibernate.engine.Status;
|
||||||
import org.hibernate.engine.SessionImplementor;
|
|
||||||
import org.hibernate.persister.entity.EntityPersister;
|
import org.hibernate.persister.entity.EntityPersister;
|
||||||
import org.hibernate.pretty.MessageHelper;
|
import org.hibernate.pretty.MessageHelper;
|
||||||
|
|
||||||
|
@ -55,7 +58,7 @@ public class AbstractLockUpgradeEventListener extends AbstractReassociateEventLi
|
||||||
* @param requestedLockMode The lock mode being requested for locking.
|
* @param requestedLockMode The lock mode being requested for locking.
|
||||||
* @param source The session which is the source of the event being processed.
|
* @param source The session which is the source of the event being processed.
|
||||||
*/
|
*/
|
||||||
protected void upgradeLock(Object object, EntityEntry entry, LockMode requestedLockMode, SessionImplementor source) {
|
protected void upgradeLock(Object object, EntityEntry entry, LockMode requestedLockMode, EventSource source) {
|
||||||
|
|
||||||
if ( requestedLockMode.greaterThan( entry.getLockMode() ) ) {
|
if ( requestedLockMode.greaterThan( entry.getLockMode() ) ) {
|
||||||
// The user requested a "greater" (i.e. more restrictive) form of
|
// The user requested a "greater" (i.e. more restrictive) form of
|
||||||
|
@ -97,13 +100,27 @@ public class AbstractLockUpgradeEventListener extends AbstractReassociateEventLi
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if ( persister.isVersioned() && requestedLockMode == LockMode.FORCE ) {
|
if ( persister.isVersioned() && (requestedLockMode == LockMode.FORCE || requestedLockMode == LockMode.PESSIMISTIC_FORCE_INCREMENT ) ) {
|
||||||
// todo : should we check the current isolation mode explicitly?
|
// todo : should we check the current isolation mode explicitly?
|
||||||
Object nextVersion = persister.forceVersionIncrement(
|
Object nextVersion = persister.forceVersionIncrement(
|
||||||
entry.getId(), entry.getVersion(), source
|
entry.getId(), entry.getVersion(), source
|
||||||
);
|
);
|
||||||
entry.forceLocked( object, nextVersion );
|
entry.forceLocked( object, nextVersion );
|
||||||
}
|
}
|
||||||
|
else if ( requestedLockMode == LockMode.OPTIMISTIC_FORCE_INCREMENT ) {
|
||||||
|
if(!persister.isVersioned()) {
|
||||||
|
throw new OptimisticLockException("force: Version column is not mapped for " + entry.getPersister().getEntityName(), object);
|
||||||
|
}
|
||||||
|
EntityIncrementVersionProcess incrementVersion = new EntityIncrementVersionProcess(object, entry);
|
||||||
|
source.getActionQueue().registerProcess(incrementVersion);
|
||||||
|
}
|
||||||
|
else if ( requestedLockMode == LockMode.OPTIMISTIC ) {
|
||||||
|
if(!persister.isVersioned()) {
|
||||||
|
throw new OptimisticLockException("Version column is not mapped for " + entry.getPersister().getEntityName(), object);
|
||||||
|
}
|
||||||
|
EntityVerifyVersionProcess verifyVersion = new EntityVerifyVersionProcess(object, entry);
|
||||||
|
source.getActionQueue().registerProcess(verifyVersion);
|
||||||
|
}
|
||||||
else {
|
else {
|
||||||
persister.lock( entry.getId(), entry.getVersion(), object, requestedLockMode, source );
|
persister.lock( entry.getId(), entry.getVersion(), object, requestedLockMode, source );
|
||||||
}
|
}
|
||||||
|
|
|
@ -485,7 +485,7 @@ public class DefaultLoadEventListener extends AbstractLockUpgradeEventListener i
|
||||||
return INCONSISTENT_RTN_CLASS_MARKER;
|
return INCONSISTENT_RTN_CLASS_MARKER;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
upgradeLock( old, oldEntry, event.getLockMode(), session );
|
upgradeLock( old, oldEntry, event.getLockMode(), event.getSession() );
|
||||||
}
|
}
|
||||||
|
|
||||||
return old;
|
return old;
|
||||||
|
|
|
@ -80,11 +80,11 @@ public class DefaultLockEventListener extends AbstractLockUpgradeEventListener i
|
||||||
}
|
}
|
||||||
|
|
||||||
entry = reassociate(event, entity, id, persister);
|
entry = reassociate(event, entity, id, persister);
|
||||||
|
// TODO: make cascadeOnLock optional based on SCOPE
|
||||||
cascadeOnLock(event, persister, entity);
|
cascadeOnLock(event, persister, entity);
|
||||||
}
|
}
|
||||||
|
|
||||||
upgradeLock( entity, entry, event.getLockMode(), source );
|
upgradeLock( entity, entry, event.getLockMode(), event.getSession() );
|
||||||
}
|
}
|
||||||
|
|
||||||
private void cascadeOnLock(LockEvent event, EntityPersister persister, Object entity) {
|
private void cascadeOnLock(LockEvent event, EntityPersister persister, Object entity) {
|
||||||
|
|
|
@ -1391,6 +1391,11 @@ public abstract class AbstractEntityPersister
|
||||||
lockers.put( LockMode.UPGRADE, generateLocker( LockMode.UPGRADE ) );
|
lockers.put( LockMode.UPGRADE, generateLocker( LockMode.UPGRADE ) );
|
||||||
lockers.put( LockMode.UPGRADE_NOWAIT, generateLocker( LockMode.UPGRADE_NOWAIT ) );
|
lockers.put( LockMode.UPGRADE_NOWAIT, generateLocker( LockMode.UPGRADE_NOWAIT ) );
|
||||||
lockers.put( LockMode.FORCE, generateLocker( LockMode.FORCE ) );
|
lockers.put( LockMode.FORCE, generateLocker( LockMode.FORCE ) );
|
||||||
|
lockers.put( LockMode.PESSIMISTIC_READ, generateLocker( LockMode.PESSIMISTIC_READ ) );
|
||||||
|
lockers.put( LockMode.PESSIMISTIC_WRITE, generateLocker( LockMode.PESSIMISTIC_WRITE ) );
|
||||||
|
lockers.put( LockMode.PESSIMISTIC_FORCE_INCREMENT, generateLocker( LockMode.PESSIMISTIC_FORCE_INCREMENT ) );
|
||||||
|
lockers.put( LockMode.OPTIMISTIC, generateLocker( LockMode.OPTIMISTIC ) );
|
||||||
|
lockers.put( LockMode.OPTIMISTIC_FORCE_INCREMENT, generateLocker( LockMode.OPTIMISTIC_FORCE_INCREMENT ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
protected LockingStrategy generateLocker(LockMode lockMode) {
|
protected LockingStrategy generateLocker(LockMode lockMode) {
|
||||||
|
@ -3129,6 +3134,26 @@ public abstract class AbstractEntityPersister
|
||||||
readLoader :
|
readLoader :
|
||||||
createEntityLoader( LockMode.FORCE )
|
createEntityLoader( LockMode.FORCE )
|
||||||
);
|
);
|
||||||
|
loaders.put(
|
||||||
|
LockMode.PESSIMISTIC_READ,
|
||||||
|
disableForUpdate ?
|
||||||
|
readLoader :
|
||||||
|
createEntityLoader( LockMode.PESSIMISTIC_READ )
|
||||||
|
);
|
||||||
|
loaders.put(
|
||||||
|
LockMode.PESSIMISTIC_WRITE,
|
||||||
|
disableForUpdate ?
|
||||||
|
readLoader :
|
||||||
|
createEntityLoader( LockMode.PESSIMISTIC_WRITE )
|
||||||
|
);
|
||||||
|
loaders.put(
|
||||||
|
LockMode.PESSIMISTIC_FORCE_INCREMENT,
|
||||||
|
disableForUpdate ?
|
||||||
|
readLoader :
|
||||||
|
createEntityLoader( LockMode.PESSIMISTIC_FORCE_INCREMENT )
|
||||||
|
);
|
||||||
|
loaders.put( LockMode.OPTIMISTIC, readLoader );
|
||||||
|
loaders.put( LockMode.OPTIMISTIC_FORCE_INCREMENT, readLoader );
|
||||||
|
|
||||||
loaders.put(
|
loaders.put(
|
||||||
"merge",
|
"merge",
|
||||||
|
|
|
@ -38,6 +38,7 @@ import javax.persistence.NonUniqueResultException;
|
||||||
import javax.persistence.OptimisticLockException;
|
import javax.persistence.OptimisticLockException;
|
||||||
import javax.persistence.PersistenceContextType;
|
import javax.persistence.PersistenceContextType;
|
||||||
import javax.persistence.PersistenceException;
|
import javax.persistence.PersistenceException;
|
||||||
|
import javax.persistence.PessimisticLockException;
|
||||||
import javax.persistence.Query;
|
import javax.persistence.Query;
|
||||||
import javax.persistence.TransactionRequiredException;
|
import javax.persistence.TransactionRequiredException;
|
||||||
import javax.persistence.TypedQuery;
|
import javax.persistence.TypedQuery;
|
||||||
|
@ -53,22 +54,7 @@ import javax.transaction.TransactionManager;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import org.hibernate.AssertionFailure;
|
import org.hibernate.*;
|
||||||
import org.hibernate.FlushMode;
|
|
||||||
import org.hibernate.HibernateException;
|
|
||||||
import org.hibernate.LockMode;
|
|
||||||
import org.hibernate.MappingException;
|
|
||||||
import org.hibernate.ObjectDeletedException;
|
|
||||||
import org.hibernate.ObjectNotFoundException;
|
|
||||||
import org.hibernate.QueryException;
|
|
||||||
import org.hibernate.SQLQuery;
|
|
||||||
import org.hibernate.Session;
|
|
||||||
import org.hibernate.StaleObjectStateException;
|
|
||||||
import org.hibernate.StaleStateException;
|
|
||||||
import org.hibernate.Transaction;
|
|
||||||
import org.hibernate.TransientObjectException;
|
|
||||||
import org.hibernate.TypeMismatchException;
|
|
||||||
import org.hibernate.UnresolvableObjectException;
|
|
||||||
import org.hibernate.cfg.Environment;
|
import org.hibernate.cfg.Environment;
|
||||||
import org.hibernate.ejb.transaction.JoinableCMTTransaction;
|
import org.hibernate.ejb.transaction.JoinableCMTTransaction;
|
||||||
import org.hibernate.ejb.util.ConfigurationHelper;
|
import org.hibernate.ejb.util.ConfigurationHelper;
|
||||||
|
@ -253,8 +239,21 @@ public abstract class AbstractEntityManagerImpl implements HibernateEntityManage
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public <A> A find(Class<A> entityClass, Object primaryKey) {
|
public <A> A find(Class<A> entityClass, Object primaryKey) {
|
||||||
|
LockModeType lmt = null;
|
||||||
|
return find( entityClass, primaryKey, lmt);
|
||||||
|
}
|
||||||
|
|
||||||
|
public <T> T find(Class<T> entityClass, Object primaryKey, Map<String, Object> properties) {
|
||||||
|
return find(entityClass, primaryKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public <A> A find(Class<A> entityClass, Object primaryKey, LockModeType lockModeType) {
|
||||||
try {
|
try {
|
||||||
return ( A ) getSession().get( entityClass, ( Serializable ) primaryKey );
|
if ( lockModeType != null )
|
||||||
|
return ( A ) getSession().get( entityClass, ( Serializable ) primaryKey, getLockMode(lockModeType) );
|
||||||
|
else
|
||||||
|
return ( A ) getSession().get( entityClass, ( Serializable ) primaryKey );
|
||||||
}
|
}
|
||||||
catch ( ObjectDeletedException e ) {
|
catch ( ObjectDeletedException e ) {
|
||||||
//the spec is silent about people doing remove() find() on the same PC
|
//the spec is silent about people doing remove() find() on the same PC
|
||||||
|
@ -278,19 +277,8 @@ public abstract class AbstractEntityManagerImpl implements HibernateEntityManage
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public <T> T find(Class<T> tClass, Object o, Map<String, Object> stringObjectMap) {
|
public <A> A find(Class<A> entityClass, Object primaryKey, LockModeType lockModeType, Map<String, Object> properties) {
|
||||||
//FIXME
|
return find(entityClass, primaryKey, lockModeType);
|
||||||
return null; //To change body of implemented methods use File | Settings | File Templates.
|
|
||||||
}
|
|
||||||
|
|
||||||
public <T> T find(Class<T> tClass, Object o, LockModeType lockModeType) {
|
|
||||||
//FIXME
|
|
||||||
return null; //To change body of implemented methods use File | Settings | File Templates.
|
|
||||||
}
|
|
||||||
|
|
||||||
public <T> T find(Class<T> tClass, Object o, LockModeType lockModeType, Map<String, Object> stringObjectMap) {
|
|
||||||
//FIXME
|
|
||||||
return null; //To change body of implemented methods use File | Settings | File Templates.
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void checkTransactionNeeded() {
|
private void checkTransactionNeeded() {
|
||||||
|
@ -346,12 +334,25 @@ public abstract class AbstractEntityManagerImpl implements HibernateEntityManage
|
||||||
}
|
}
|
||||||
|
|
||||||
public void refresh(Object entity) {
|
public void refresh(Object entity) {
|
||||||
|
LockModeType lmt = null;
|
||||||
|
refresh(entity, lmt);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void refresh(Object entity, Map<String, Object> properties) {
|
||||||
|
LockModeType lmt = null;
|
||||||
|
refresh(entity, lmt);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void refresh(Object entity, LockModeType lockModeType) {
|
||||||
checkTransactionNeeded();
|
checkTransactionNeeded();
|
||||||
try {
|
try {
|
||||||
if ( !getSession().contains( entity ) ) {
|
if ( !getSession().contains( entity ) ) {
|
||||||
throw new IllegalArgumentException( "Entity not managed" );
|
throw new IllegalArgumentException( "Entity not managed" );
|
||||||
}
|
}
|
||||||
getSession().refresh( entity );
|
if(lockModeType != null)
|
||||||
|
getSession().refresh( entity, getLockMode(lockModeType) );
|
||||||
|
else
|
||||||
|
getSession().refresh( entity );
|
||||||
}
|
}
|
||||||
catch ( MappingException e ) {
|
catch ( MappingException e ) {
|
||||||
throw new IllegalArgumentException( e.getMessage(), e );
|
throw new IllegalArgumentException( e.getMessage(), e );
|
||||||
|
@ -361,19 +362,8 @@ public abstract class AbstractEntityManagerImpl implements HibernateEntityManage
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void refresh(Object o, Map<String, Object> stringObjectMap) {
|
public void refresh(Object entity, LockModeType lockModeType, Map<String, Object> properties) {
|
||||||
//FIXME
|
refresh(entity, lockModeType);
|
||||||
//To change body of implemented methods use File | Settings | File Templates.
|
|
||||||
}
|
|
||||||
|
|
||||||
public void refresh(Object o, LockModeType lockModeType) {
|
|
||||||
//FIXME
|
|
||||||
//To change body of implemented methods use File | Settings | File Templates.
|
|
||||||
}
|
|
||||||
|
|
||||||
public void refresh(Object o, LockModeType lockModeType, Map<String, Object> stringObjectMap) {
|
|
||||||
//FIXME
|
|
||||||
//To change body of implemented methods use File | Settings | File Templates.
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean contains(Object entity) {
|
public boolean contains(Object entity) {
|
||||||
|
@ -393,9 +383,11 @@ public abstract class AbstractEntityManagerImpl implements HibernateEntityManage
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public LockModeType getLockMode(Object o) {
|
public LockModeType getLockMode(Object entity) {
|
||||||
//FIXME
|
if ( !contains( entity ) ) {
|
||||||
return null; //To change body of implemented methods use File | Settings | File Templates.
|
throw new IllegalArgumentException( "entity not in the persistence context" );
|
||||||
|
}
|
||||||
|
return this.getLockModeType(getSession().getCurrentLockMode(entity));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setProperty(String s, Object o) {
|
public void setProperty(String s, Object o) {
|
||||||
|
@ -527,21 +519,57 @@ public abstract class AbstractEntityManagerImpl implements HibernateEntityManage
|
||||||
getSession().lock( entity, getLockMode( lockMode ) );
|
getSession().lock( entity, getLockMode( lockMode ) );
|
||||||
}
|
}
|
||||||
catch ( HibernateException he ) {
|
catch ( HibernateException he ) {
|
||||||
throwPersistenceException( he );
|
throw convert( he );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void lock(Object o, LockModeType lockModeType, Map<String, Object> stringObjectMap) {
|
public void lock(Object o, LockModeType lockModeType, Map<String, Object> properties) {
|
||||||
//FIXME
|
// todo: support different properties passed in
|
||||||
//To change body of implemented methods use File | Settings | File Templates.
|
lock(o,lockModeType);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private LockModeType getLockModeType(LockMode lockMode)
|
||||||
|
{
|
||||||
|
if ( lockMode == LockMode.NONE )
|
||||||
|
return LockModeType.NONE;
|
||||||
|
else if ( lockMode == LockMode.OPTIMISTIC || lockMode == LockMode.READ )
|
||||||
|
return LockModeType.OPTIMISTIC;
|
||||||
|
else if ( lockMode == LockMode.OPTIMISTIC_FORCE_INCREMENT || lockMode == LockMode.WRITE )
|
||||||
|
return LockModeType.OPTIMISTIC_FORCE_INCREMENT;
|
||||||
|
else if ( lockMode == LockMode.PESSIMISTIC_READ )
|
||||||
|
return LockModeType.PESSIMISTIC_READ;
|
||||||
|
else if ( lockMode == LockMode.PESSIMISTIC_WRITE )
|
||||||
|
return LockModeType.PESSIMISTIC_WRITE;
|
||||||
|
else if ( lockMode == LockMode.PESSIMISTIC_FORCE_INCREMENT )
|
||||||
|
return LockModeType.PESSIMISTIC_FORCE_INCREMENT;
|
||||||
|
throw new AssertionFailure("unhandled lock mode " + lockMode );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
private LockMode getLockMode(LockModeType lockMode) {
|
private LockMode getLockMode(LockModeType lockMode) {
|
||||||
switch ( lockMode ) {
|
switch ( lockMode ) {
|
||||||
|
|
||||||
case READ:
|
case READ:
|
||||||
return LockMode.UPGRADE; //assuming we are on read-commited and we need to prevent non repeteable read
|
case OPTIMISTIC:
|
||||||
|
return LockMode.OPTIMISTIC;
|
||||||
|
|
||||||
|
case OPTIMISTIC_FORCE_INCREMENT:
|
||||||
case WRITE:
|
case WRITE:
|
||||||
return LockMode.FORCE;
|
return LockMode.OPTIMISTIC_FORCE_INCREMENT;
|
||||||
|
|
||||||
|
case PESSIMISTIC_READ:
|
||||||
|
return LockMode.PESSIMISTIC_READ;
|
||||||
|
|
||||||
|
case PESSIMISTIC_WRITE:
|
||||||
|
return LockMode.PESSIMISTIC_WRITE;
|
||||||
|
|
||||||
|
case PESSIMISTIC_FORCE_INCREMENT:
|
||||||
|
return LockMode.PESSIMISTIC_FORCE_INCREMENT;
|
||||||
|
|
||||||
|
case NONE:
|
||||||
|
return LockMode.NONE;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
throw new AssertionFailure( "Unknown LockModeType: " + lockMode );
|
throw new AssertionFailure( "Unknown LockModeType: " + lockMode );
|
||||||
}
|
}
|
||||||
|
@ -772,6 +800,16 @@ public abstract class AbstractEntityManagerImpl implements HibernateEntityManage
|
||||||
handlePersistenceException( converted );
|
handlePersistenceException( converted );
|
||||||
return converted;
|
return converted;
|
||||||
}
|
}
|
||||||
|
else if ( e instanceof org.hibernate.OptimisticLockException ) {
|
||||||
|
PersistenceException converted = wrapLockException(e);
|
||||||
|
handlePersistenceException( converted );
|
||||||
|
return converted;
|
||||||
|
}
|
||||||
|
else if ( e instanceof org.hibernate.PessimisticLockException ) {
|
||||||
|
PersistenceException converted = wrapLockException(e);
|
||||||
|
handlePersistenceException( converted );
|
||||||
|
return converted;
|
||||||
|
}
|
||||||
else if ( e instanceof ObjectNotFoundException ) {
|
else if ( e instanceof ObjectNotFoundException ) {
|
||||||
EntityNotFoundException converted = new EntityNotFoundException( e.getMessage() );
|
EntityNotFoundException converted = new EntityNotFoundException( e.getMessage() );
|
||||||
handlePersistenceException( converted );
|
handlePersistenceException( converted );
|
||||||
|
@ -846,4 +884,21 @@ public abstract class AbstractEntityManagerImpl implements HibernateEntityManage
|
||||||
}
|
}
|
||||||
return pe;
|
return pe;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public PersistenceException wrapLockException(HibernateException e) {
|
||||||
|
PersistenceException pe;
|
||||||
|
if ( e instanceof org.hibernate.OptimisticLockException ) {
|
||||||
|
org.hibernate.OptimisticLockException ole = (org.hibernate.OptimisticLockException)e;
|
||||||
|
pe = new OptimisticLockException(ole.getMessage(), ole, ole.getEntity());
|
||||||
|
}
|
||||||
|
else if ( e instanceof org.hibernate.PessimisticLockException ) {
|
||||||
|
org.hibernate.PessimisticLockException ple = (org.hibernate.PessimisticLockException)e;
|
||||||
|
pe = new PessimisticLockException(ple.getMessage(), ple, ple.getEntity());
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
pe = new OptimisticLockException( e );
|
||||||
|
}
|
||||||
|
return pe;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -242,6 +242,17 @@ public abstract class AbstractQueryImpl<X> implements TypedQuery<X> {
|
||||||
return QueryHints.getDefinedHints();
|
return QueryHints.getDefinedHints();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private javax.persistence.LockModeType jpaLockMode = javax.persistence.LockModeType.NONE;
|
||||||
|
|
||||||
|
public TypedQuery<X> setLockMode(javax.persistence.LockModeType lockModeType) {
|
||||||
|
this.jpaLockMode = lockModeType;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public javax.persistence.LockModeType getLockMode() {
|
||||||
|
return jpaLockMode;
|
||||||
|
}
|
||||||
|
|
||||||
private FlushModeType jpaFlushMode;
|
private FlushModeType jpaFlushMode;
|
||||||
|
|
||||||
public TypedQuery<X> setFlushMode(FlushModeType jpaFlushMode) {
|
public TypedQuery<X> setFlushMode(FlushModeType jpaFlushMode) {
|
||||||
|
|
|
@ -29,7 +29,7 @@ import java.util.Date;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import javax.persistence.LockModeType;
|
|
||||||
import javax.persistence.NoResultException;
|
import javax.persistence.NoResultException;
|
||||||
import javax.persistence.NonUniqueResultException;
|
import javax.persistence.NonUniqueResultException;
|
||||||
import javax.persistence.Parameter;
|
import javax.persistence.Parameter;
|
||||||
|
@ -547,21 +547,6 @@ public class QueryImpl<X> extends org.hibernate.ejb.AbstractQueryImpl<X> impleme
|
||||||
return param;
|
return param;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritDoc}
|
|
||||||
*/
|
|
||||||
public TypedQuery<X> setLockMode(LockModeType lockModeType) {
|
|
||||||
// TODO : aye aye aye
|
|
||||||
throw new UnsupportedOperationException( "Not yet implemented" );
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritDoc}
|
|
||||||
*/
|
|
||||||
public LockModeType getLockMode() {
|
|
||||||
return LockModeType.NONE;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@inheritDoc}
|
* {@inheritDoc}
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -3,6 +3,7 @@ package org.hibernate.ejb.test.lock;
|
||||||
|
|
||||||
import javax.persistence.EntityManager;
|
import javax.persistence.EntityManager;
|
||||||
import javax.persistence.LockModeType;
|
import javax.persistence.LockModeType;
|
||||||
|
import javax.persistence.OptimisticLockException;
|
||||||
|
|
||||||
import org.hibernate.ejb.test.TestCase;
|
import org.hibernate.ejb.test.TestCase;
|
||||||
|
|
||||||
|
@ -34,6 +35,29 @@ public class LockTest extends TestCase {
|
||||||
em.close();
|
em.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void testLockOptimistic() throws Exception {
|
||||||
|
Lock lock = new Lock();
|
||||||
|
lock.setName( "name" );
|
||||||
|
EntityManager em = getOrCreateEntityManager();
|
||||||
|
em.getTransaction().begin();
|
||||||
|
em.persist( lock );
|
||||||
|
em.getTransaction().commit();
|
||||||
|
|
||||||
|
em.getTransaction().begin();
|
||||||
|
lock = em.getReference( Lock.class, lock.getId() );
|
||||||
|
em.lock( lock, LockModeType.OPTIMISTIC );
|
||||||
|
lock.setName( "surname" );
|
||||||
|
em.getTransaction().commit();
|
||||||
|
|
||||||
|
em.getTransaction().begin();
|
||||||
|
lock = em.find( Lock.class, lock.getId() );
|
||||||
|
assertEquals( "surname", lock.getName() );
|
||||||
|
em.remove( lock );
|
||||||
|
em.getTransaction().commit();
|
||||||
|
|
||||||
|
em.close();
|
||||||
|
}
|
||||||
|
|
||||||
public void testLockWrite() throws Exception {
|
public void testLockWrite() throws Exception {
|
||||||
Lock lock = new Lock();
|
Lock lock = new Lock();
|
||||||
lock.setName( "second" );
|
lock.setName( "second" );
|
||||||
|
@ -70,7 +94,19 @@ public class LockTest extends TestCase {
|
||||||
|
|
||||||
em.getTransaction().begin();
|
em.getTransaction().begin();
|
||||||
lock = em.getReference( UnversionedLock.class, lock.getId() );
|
lock = em.getReference( UnversionedLock.class, lock.getId() );
|
||||||
em.lock( lock, LockModeType.READ );
|
try {
|
||||||
|
// getting a READ (optimistic) lock on unversioned entity is not expected to work.
|
||||||
|
// To get the same functionality as prior release, change the LockModeType.READ lock to:
|
||||||
|
// em.lock(lock,LockModeType.PESSIMISTIC_READ);
|
||||||
|
em.lock( lock, LockModeType.READ );
|
||||||
|
fail("expected OptimisticLockException exception");
|
||||||
|
} catch(OptimisticLockException expected) {}
|
||||||
|
em.getTransaction().rollback();
|
||||||
|
|
||||||
|
// the previous code block can be rewritten as follows (to get the previous behavior)
|
||||||
|
em.getTransaction().begin();
|
||||||
|
lock = em.getReference( UnversionedLock.class, lock.getId() );
|
||||||
|
em.lock( lock, LockModeType.PESSIMISTIC_READ );
|
||||||
em.getTransaction().commit();
|
em.getTransaction().commit();
|
||||||
|
|
||||||
em.getTransaction().begin();
|
em.getTransaction().begin();
|
||||||
|
@ -80,6 +116,58 @@ public class LockTest extends TestCase {
|
||||||
em.close();
|
em.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void testLockPessimisticForceIncrement() throws Exception {
|
||||||
|
Lock lock = new Lock();
|
||||||
|
lock.setName( "force" );
|
||||||
|
EntityManager em = getOrCreateEntityManager();
|
||||||
|
em.getTransaction().begin();
|
||||||
|
em.persist( lock );
|
||||||
|
em.getTransaction().commit();
|
||||||
|
|
||||||
|
em.getTransaction().begin();
|
||||||
|
lock = em.getReference( Lock.class, lock.getId() );
|
||||||
|
Integer version = lock.getVersion();
|
||||||
|
em.lock( lock, LockModeType.PESSIMISTIC_FORCE_INCREMENT );
|
||||||
|
em.getTransaction().commit();
|
||||||
|
|
||||||
|
em.getTransaction().begin();
|
||||||
|
lock = em.getReference( Lock.class, lock.getId() );
|
||||||
|
try {
|
||||||
|
assertEquals( "should increase the version number ", 1, lock.getVersion() - version );
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
em.remove( lock );
|
||||||
|
em.getTransaction().commit();
|
||||||
|
}
|
||||||
|
em.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testLockOptimisticForceIncrement() throws Exception {
|
||||||
|
Lock lock = new Lock();
|
||||||
|
lock.setName( "force" );
|
||||||
|
EntityManager em = getOrCreateEntityManager();
|
||||||
|
em.getTransaction().begin();
|
||||||
|
em.persist( lock );
|
||||||
|
em.getTransaction().commit();
|
||||||
|
|
||||||
|
em.getTransaction().begin();
|
||||||
|
lock = em.getReference( Lock.class, lock.getId() );
|
||||||
|
Integer version = lock.getVersion();
|
||||||
|
em.lock( lock, LockModeType.OPTIMISTIC_FORCE_INCREMENT );
|
||||||
|
em.getTransaction().commit();
|
||||||
|
|
||||||
|
em.getTransaction().begin();
|
||||||
|
lock = em.getReference( Lock.class, lock.getId() );
|
||||||
|
try {
|
||||||
|
assertEquals( "should increase the version number ", 1, lock.getVersion() - version );
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
em.remove( lock );
|
||||||
|
em.getTransaction().commit();
|
||||||
|
}
|
||||||
|
em.close();
|
||||||
|
}
|
||||||
|
|
||||||
public Class[] getAnnotatedClasses() {
|
public Class[] getAnnotatedClasses() {
|
||||||
return new Class[]{
|
return new Class[]{
|
||||||
Lock.class,
|
Lock.class,
|
||||||
|
|
|
@ -51,7 +51,7 @@ public class JPALockTest extends AbstractJPATest {
|
||||||
* must always prevent the phenomena P1 and P2. Applications that call lock(entity, LockModeType.READ)
|
* must always prevent the phenomena P1 and P2. Applications that call lock(entity, LockModeType.READ)
|
||||||
* on non-versioned objects will not be portable.
|
* on non-versioned objects will not be portable.
|
||||||
* <p/>
|
* <p/>
|
||||||
* Odd as it may sound, EJB3 LockModeType.READ actually maps to the Hibernate LockMode.UPGRADE
|
* EJB3 LockModeType.READ actually maps to the Hibernate LockMode.OPTIMISTIC
|
||||||
*/
|
*/
|
||||||
public void testLockModeTypeRead() {
|
public void testLockModeTypeRead() {
|
||||||
if ( !readCommittedIsolationMaintained( "ejb3 lock tests" ) ) {
|
if ( !readCommittedIsolationMaintained( "ejb3 lock tests" ) ) {
|
||||||
|
|
Loading…
Reference in New Issue