HHH-4546 JPA-2.0 locking. More pessimistic lock exception support and timeout exception support

git-svn-id: https://svn.jboss.org/repos/hibernate/core/trunk@18209 1b8cb986-b30d-0410-93ca-fae66ebed9b2
This commit is contained in:
Scott Marlow 2009-12-11 13:23:17 +00:00
parent 2fef8a4acc
commit 18bb17061f
6 changed files with 86 additions and 27 deletions

View File

@ -24,29 +24,33 @@
*/
package org.hibernate;
import java.sql.SQLException;
/**
*
* Throw when an pessimistic locking conflict occurs.
* Thrown when a pessimistic locking conflict occurs.
*
* @author Scott Marlow
*/
public class PessimisticLockException extends HibernateException {
public class PessimisticLockException extends JDBCException {
Object entity;
public PessimisticLockException(String s) {
super(s);
}
public PessimisticLockException(String s, Throwable throwable, Object entity) {
super(s, throwable);
public PessimisticLockException(String s, JDBCException je, Object entity) {
super(s, je.getSQLException());
this.entity = entity;
}
public PessimisticLockException(String s, SQLException se, Object entity) {
super(s, se);
this.entity = entity;
}
public PessimisticLockException(String s, Object entity) {
super(s);
this.entity = entity;
}
public PessimisticLockException(String s, SQLException se, String sql) {
super(s, se, sql);
this.entity = null;
}
public Object getEntity() {
return entity;

View File

@ -25,6 +25,7 @@
package org.hibernate.exception;
import org.hibernate.JDBCException;
import org.hibernate.PessimisticLockException;
import java.sql.SQLException;
import java.util.HashSet;
@ -109,6 +110,11 @@ public class SQLStateConverter implements SQLExceptionConverter {
// oracle sql-state code for deadlock
return new LockAcquisitionException( message, sqlException, sql );
}
if ( "40XL1".equals( sqlState ) || "40XL2".equals( sqlState )) {
// Derby "A lock could not be obtained within the time requested."
return new PessimisticLockException( message, sqlException, sql );
}
}
return handledNonSpecificException( sqlException, message, sql );

View File

@ -214,13 +214,34 @@ public abstract class Loader {
return null;
}
private Map buildLockMap(Map locks) {
Map result = locks;
if ( result == null ) {
LockOptions[] lockArray = getLockOptions(result);
String[] aliases = getAliases();
if (aliases != null &&
lockArray != null &&
lockArray.length > 0 &&
lockArray.length == aliases.length &&
lockArray[0].getLockMode() != LockMode.NONE ) {
result = new HashMap();
for ( int looper = 0; looper < lockArray.length; looper++ ) {
result.put(aliases[looper], lockArray[looper]);
}
}
}
return result;
}
/**
* Modify the SQL, adding lock hints and comments, if necessary
*/
protected String preprocessSQL(String sql, QueryParameters parameters, Dialect dialect)
throws HibernateException {
sql = applyLocks( sql, parameters.getLockOptions(), dialect );
Map locks = buildLockMap(parameters.getLockOptions());
sql = applyLocks( sql, locks, dialect );
return getFactory().getSettings().isCommentsEnabled() ?
prependComment( sql, parameters ) : sql;
@ -700,9 +721,9 @@ public abstract class Loader {
//
// Would need to change the way the max-row stuff is handled (i.e. behind an interface) so
// that I could do the control breaking at the means to know when to stop
final LockOptions[] lockOptionsArray = getLockOptions( queryParameters.getLockOptions() );
final EntityKey optionalObjectKey = getOptionalObjectKey( queryParameters, session );
final EntityKey optionalObjectKey = getOptionalObjectKey( queryParameters, session );
final LockOptions[] lockOptionsArray = getLockOptions( queryParameters.getLockOptions() );
final boolean createSubselects = isSubselectLoadingEnabled();
final List subselectResultKeys = createSubselects ? new ArrayList() : null;
final List results = new ArrayList();

View File

@ -25,9 +25,7 @@
package org.hibernate.loader;
import java.util.Map;
import java.util.Set;
import org.hibernate.LockMode;
import org.hibernate.LockOptions;
import org.hibernate.dialect.Dialect;
import org.hibernate.engine.SessionFactoryImplementor;

View File

@ -257,9 +257,11 @@ public abstract class AbstractEntityManagerImpl implements HibernateEntityManage
}
public <A> A find(Class<A> entityClass, Object primaryKey, LockModeType lockModeType, Map<String, Object> properties) {
LockOptions lockOptions = null;
try {
if ( lockModeType != null )
return ( A ) getSession().get( entityClass, ( Serializable ) primaryKey, getLockRequest(lockModeType, properties) );
return ( A ) getSession().get( entityClass, ( Serializable ) primaryKey,
( lockOptions = getLockRequest(lockModeType, properties) ) );
else
return ( A ) getSession().get( entityClass, ( Serializable ) primaryKey );
}
@ -281,7 +283,7 @@ public abstract class AbstractEntityManagerImpl implements HibernateEntityManage
throw new IllegalArgumentException( e.getMessage(), e );
}
catch ( HibernateException he ) {
throw convert( he );
throw convert( he , lockOptions );
}
}
@ -351,12 +353,13 @@ public abstract class AbstractEntityManagerImpl implements HibernateEntityManage
public void refresh(Object entity, LockModeType lockModeType, Map<String, Object> properties) {
checkTransactionNeeded();
LockOptions lockOptions = null;
try {
if ( !getSession().contains( entity ) ) {
throw new IllegalArgumentException( "Entity not managed" );
}
if(lockModeType != null)
getSession().refresh( entity, getLockRequest(lockModeType, properties) );
getSession().refresh( entity, (lockOptions = getLockRequest(lockModeType, properties) ) );
else
getSession().refresh( entity );
}
@ -364,7 +367,7 @@ public abstract class AbstractEntityManagerImpl implements HibernateEntityManage
throw new IllegalArgumentException( e.getMessage(), e );
}
catch ( HibernateException he ) {
throw convert( he );
throw convert( he, lockOptions);
}
}
@ -515,6 +518,7 @@ public abstract class AbstractEntityManagerImpl implements HibernateEntityManage
}
public void lock(Object entity, LockModeType lockModeType, Map<String, Object> properties) {
LockOptions lockOptions = null;
try {
if ( !isTransactionInProgress() ) {
throw new TransactionRequiredException( "no transaction is in progress" );
@ -523,10 +527,10 @@ public abstract class AbstractEntityManagerImpl implements HibernateEntityManage
if ( !contains( entity ) ) {
throw new IllegalArgumentException( "entity not in the persistence context" );
}
getSession().buildLockRequest(getLockRequest(lockModeType, properties)).lock( entity );
getSession().buildLockRequest( (lockOptions = getLockRequest(lockModeType, properties))).lock( entity );
}
catch ( HibernateException he ) {
throw convert( he );
throw convert( he , lockOptions);
}
}
@ -835,18 +839,25 @@ public abstract class AbstractEntityManagerImpl implements HibernateEntityManage
* {@inheritDoc}
*/
public RuntimeException convert(HibernateException e) {
return convert(e, null);
}
/**
* {@inheritDoc}
*/
public RuntimeException convert(HibernateException e, LockOptions lockOptions) {
if ( e instanceof StaleStateException ) {
PersistenceException converted = wrapStaleStateException( ( StaleStateException ) e );
handlePersistenceException( converted );
return converted;
}
else if ( e instanceof org.hibernate.OptimisticLockException ) {
PersistenceException converted = wrapLockException(e);
PersistenceException converted = wrapLockException(e, lockOptions);
handlePersistenceException( converted );
return converted;
}
else if ( e instanceof org.hibernate.PessimisticLockException ) {
PersistenceException converted = wrapLockException(e);
PersistenceException converted = wrapLockException(e, lockOptions);
handlePersistenceException( converted );
return converted;
}
@ -925,7 +936,7 @@ public abstract class AbstractEntityManagerImpl implements HibernateEntityManage
return pe;
}
public PersistenceException wrapLockException(HibernateException e) {
public PersistenceException wrapLockException(HibernateException e, LockOptions lockOptions) {
PersistenceException pe;
if ( e instanceof org.hibernate.OptimisticLockException ) {
org.hibernate.OptimisticLockException ole = (org.hibernate.OptimisticLockException)e;
@ -933,7 +944,13 @@ public abstract class AbstractEntityManagerImpl implements HibernateEntityManage
}
else if ( e instanceof org.hibernate.PessimisticLockException ) {
org.hibernate.PessimisticLockException ple = (org.hibernate.PessimisticLockException)e;
pe = new PessimisticLockException(ple.getMessage(), ple, ple.getEntity());
if (lockOptions !=null && lockOptions.getTimeOut() > -1) {
// assume lock timeout occurred if a timeout or NO WAIT was specified
pe = new LockTimeoutException(ple.getMessage(), ple, ple.getEntity());
}
else {
pe = new PessimisticLockException(ple.getMessage(), ple, ple.getEntity());
}
}
else {
pe = new OptimisticLockException( e );

View File

@ -27,6 +27,7 @@ import javax.persistence.PersistenceException;
import org.hibernate.HibernateException;
import org.hibernate.StaleStateException;
import org.hibernate.LockOptions;
/**
* Additional internal contracts for the Hibernate {@link javax.persistence.EntityManager} implementation.
@ -57,6 +58,18 @@ public interface HibernateEntityManagerImplementor extends HibernateEntityManage
*/
public void throwPersistenceException(PersistenceException e);
/**
* Converts a Hibernate-specific exception into a JPA-specified exception; note that the JPA sepcification makes use
* of exceptions outside its exception hierarchy, though they are all runtime exceptions.
* <p/>
* Any appropriate/needed calls to {@link #handlePersistenceException} are also made.
*
* @param e The Hibernate excepton.
* @param lockOptions The lock options in effect at the time of exception (can be null)
* @return The JPA-specified exception
*/
public RuntimeException convert(HibernateException e, LockOptions lockOptions);
/**
* Converts a Hibernate-specific exception into a JPA-specified exception; note that the JPA sepcification makes use
* of exceptions outside its exception hierarchy, though they are all runtime exceptions.