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:
parent
2fef8a4acc
commit
18bb17061f
|
@ -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;
|
||||
|
|
|
@ -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 );
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 );
|
||||
|
|
|
@ -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.
|
||||
|
|
Loading…
Reference in New Issue