HHH-6865 - PessimisticLockException should be thrown when pessimistic read and write locking strategies fail

This commit is contained in:
Steve Ebersole 2011-11-30 12:19:24 -06:00
parent 3577cbde08
commit eb59e81bb9
17 changed files with 332 additions and 250 deletions

View File

@ -1,10 +1,10 @@
/* /*
* Hibernate, Relational Persistence for Idiomatic Java * Hibernate, Relational Persistence for Idiomatic Java
* *
* Copyright (c) 2009, Red Hat Middleware LLC or third-party contributors as * Copyright (c) 2009-2011, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution * indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are * statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Middleware LLC. * distributed under license by Red Hat Inc.
* *
* This copyrighted material is made available to anyone wishing to use, modify, * 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 * copy, or redistribute it subject to the terms and conditions of the GNU
@ -20,33 +20,20 @@
* Free Software Foundation, Inc. * Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor * 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA * Boston, MA 02110-1301 USA
*
*/ */
package org.hibernate; package org.hibernate;
import org.hibernate.dialect.lock.OptimisticEntityLockException;
/** /**
*
* Throw when an optimistic locking conflict occurs. * Throw when an optimistic locking conflict occurs.
* *
* @author Scott Marlow * @author Scott Marlow
*
* @deprecated Use {@link org.hibernate.dialect.lock.OptimisticEntityLockException} instead
*/ */
public class OptimisticLockException extends HibernateException { public class OptimisticLockException extends OptimisticEntityLockException {
public OptimisticLockException(Object entity, String message) {
Object entity; super( entity, message );
public OptimisticLockException(String s) {
super(s);
} }
public OptimisticLockException(String s, Object entity) {
super(s);
this.entity = entity;
}
public Object getEntity() {
return entity;
}
} }

View File

@ -1,10 +1,10 @@
/* /*
* Hibernate, Relational Persistence for Idiomatic Java * Hibernate, Relational Persistence for Idiomatic Java
* *
* Copyright (c) 2009, Red Hat Middleware LLC or third-party contributors as * Copyright (c) 2009-2011, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution * indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are * statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Middleware LLC. * distributed under license by Red Hat Inc.
* *
* This copyrighted material is made available to anyone wishing to use, modify, * 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 * copy, or redistribute it subject to the terms and conditions of the GNU
@ -20,39 +20,18 @@
* Free Software Foundation, Inc. * Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor * 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA * Boston, MA 02110-1301 USA
*
*/ */
package org.hibernate; package org.hibernate;
import java.sql.SQLException; import java.sql.SQLException;
/** /**
*
* Thrown when a pessimistic locking conflict occurs. * Thrown when a pessimistic locking conflict occurs.
* *
* @author Scott Marlow * @author Scott Marlow
*/ */
public class PessimisticLockException extends JDBCException { public class PessimisticLockException extends JDBCException {
Object entity;
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, SQLException se, String sql) { public PessimisticLockException(String s, SQLException se, String sql) {
super(s, se, sql); super( s, se, sql );
this.entity = null;
}
public Object getEntity() {
return entity;
} }
} }

View File

@ -52,6 +52,7 @@ public class EntityVerifyVersionProcess implements BeforeTransactionCompletionPr
Object latestVersion = persister.getCurrentVersion( entry.getId(), session ); Object latestVersion = persister.getCurrentVersion( entry.getId(), session );
if ( !entry.getVersion().equals( latestVersion ) ) { if ( !entry.getVersion().equals( latestVersion ) ) {
throw new OptimisticLockException( throw new OptimisticLockException(
object,
"Newer version [" + latestVersion + "Newer version [" + latestVersion +
"] of entity [" + MessageHelper.infoString( entry.getEntityName(), entry.getId() ) + "] of entity [" + MessageHelper.infoString( entry.getEntityName(), entry.getId() ) +
"] found in database" "] found in database"

View File

@ -51,10 +51,10 @@ public interface LockingStrategy {
* @param object The object logically being locked (currently not used) * @param object The object logically being locked (currently not used)
* @param timeout timeout in milliseconds, 0 = no wait, -1 = wait indefinitely * @param timeout timeout in milliseconds, 0 = no wait, -1 = wait indefinitely
* @param session The session from which the lock request originated * @param session The session from which the lock request originated
* @throws StaleObjectStateException Indicates an optimistic lock failure * @throws StaleObjectStateException Indicates an inability to locate the database row as part of acquiring
* as part of acquiring the requested database lock. * the requested lock.
* @throws JDBCException Indicates errors from the <tt>JDBC</tt> driver. * @throws LockingStrategyException Indicates a failure in the lock attempt
*/ */
public void lock(Serializable id, Object version, Object object, int timeout, SessionImplementor session) public void lock(Serializable id, Object version, Object object, int timeout, SessionImplementor session)
throws StaleObjectStateException, JDBCException; throws StaleObjectStateException, LockingStrategyException;
} }

View File

@ -0,0 +1,49 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2011, Red Hat Inc. 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 Inc.
*
* 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.dialect.lock;
import org.hibernate.HibernateException;
/**
* Represents an error trying to apply a {@link LockingStrategy} to an entity
*
* @author Steve Ebersole
*/
public abstract class LockingStrategyException extends HibernateException {
private final Object entity;
public LockingStrategyException(Object entity, String message) {
super( message );
this.entity = entity;
}
public LockingStrategyException(Object entity, String message, Throwable root) {
super( message, root );
this.entity = entity;
}
public Object getEntity() {
return entity;
}
}

View File

@ -0,0 +1,39 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2011, Red Hat Inc. 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 Inc.
*
* 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.dialect.lock;
/**
* Represents an error trying to apply an optimistic {@link LockingStrategy} to an entity
*
* @author Steve Ebersole
*/
public class OptimisticEntityLockException extends LockingStrategyException {
public OptimisticEntityLockException(Object entity, String message) {
super( entity, message );
}
public OptimisticEntityLockException(Object entity, String message, Throwable root) {
super( entity, message, root );
}
}

View File

@ -22,12 +22,11 @@
* Boston, MA 02110-1301 USA * Boston, MA 02110-1301 USA
*/ */
package org.hibernate.dialect.lock; package org.hibernate.dialect.lock;
import java.io.Serializable; import java.io.Serializable;
import org.hibernate.HibernateException; import org.hibernate.HibernateException;
import org.hibernate.JDBCException;
import org.hibernate.LockMode; import org.hibernate.LockMode;
import org.hibernate.StaleObjectStateException;
import org.hibernate.action.internal.EntityIncrementVersionProcess; import org.hibernate.action.internal.EntityIncrementVersionProcess;
import org.hibernate.engine.spi.EntityEntry; import org.hibernate.engine.spi.EntityEntry;
import org.hibernate.engine.spi.SessionImplementor; import org.hibernate.engine.spi.SessionImplementor;
@ -61,14 +60,8 @@ public class OptimisticForceIncrementLockingStrategy implements LockingStrategy
} }
} }
/** @Override
* @see LockingStrategy#lock public void lock(Serializable id, Object version, Object object, int timeout, SessionImplementor session) {
*/
public void lock(
Serializable id,
Object version,
Object object,
int timeout, SessionImplementor session) throws StaleObjectStateException, JDBCException {
if ( !lockable.isVersioned() ) { if ( !lockable.isVersioned() ) {
throw new HibernateException( "[" + lockMode + "] not supported for non-versioned entities [" + lockable.getEntityName() + "]" ); throw new HibernateException( "[" + lockMode + "] not supported for non-versioned entities [" + lockable.getEntityName() + "]" );
} }

View File

@ -22,6 +22,7 @@
* Boston, MA 02110-1301 USA * Boston, MA 02110-1301 USA
*/ */
package org.hibernate.dialect.lock; package org.hibernate.dialect.lock;
import java.io.Serializable; import java.io.Serializable;
import org.hibernate.HibernateException; import org.hibernate.HibernateException;
@ -40,9 +41,8 @@ import org.hibernate.persister.entity.Lockable;
* <p/> * <p/>
* This strategy is valid for LockMode.OPTIMISTIC * This strategy is valid for LockMode.OPTIMISTIC
* *
* @since 3.5
*
* @author Scott Marlow * @author Scott Marlow
* @since 3.5
*/ */
public class OptimisticLockingStrategy implements LockingStrategy { public class OptimisticLockingStrategy implements LockingStrategy {
@ -53,7 +53,7 @@ public class OptimisticLockingStrategy implements LockingStrategy {
* Construct locking strategy. * Construct locking strategy.
* *
* @param lockable The metadata for the entity to be locked. * @param lockable The metadata for the entity to be locked.
* @param lockMode Indictates the type of lock to be acquired. * @param lockMode Indicates the type of lock to be acquired.
*/ */
public OptimisticLockingStrategy(Lockable lockable, LockMode lockMode) { public OptimisticLockingStrategy(Lockable lockable, LockMode lockMode) {
this.lockable = lockable; this.lockable = lockable;
@ -63,16 +63,10 @@ public class OptimisticLockingStrategy implements LockingStrategy {
} }
} }
/** @Override
* @see org.hibernate.dialect.lock.LockingStrategy#lock public void lock(Serializable id, Object version, Object object, int timeout, SessionImplementor session) {
*/
public void lock(
Serializable id,
Object version,
Object object,
int timeout, SessionImplementor session) throws StaleObjectStateException, JDBCException {
if ( !lockable.isVersioned() ) { if ( !lockable.isVersioned() ) {
throw new OptimisticLockException( "[" + lockMode + "] not supported for non-versioned entities [" + lockable.getEntityName() + "]" ); throw new OptimisticLockException( object, "[" + lockMode + "] not supported for non-versioned entities [" + lockable.getEntityName() + "]" );
} }
EntityEntry entry = session.getPersistenceContext().getEntry(object); EntityEntry entry = session.getPersistenceContext().getEntry(object);
EventSource source = (EventSource)session; EventSource source = (EventSource)session;

View File

@ -0,0 +1,37 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2011, Red Hat Inc. 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 Inc.
*
* 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.dialect.lock;
import org.hibernate.JDBCException;
/**
* Represents an error trying to apply a pessimistic {@link LockingStrategy} to an entity
*
* @author Steve Ebersole
*/
public class PessimisticEntityLockException extends LockingStrategyException {
public PessimisticEntityLockException(Object entity, String message, JDBCException root) {
super( entity, message, root );
}
}

View File

@ -22,12 +22,11 @@
* Boston, MA 02110-1301 USA * Boston, MA 02110-1301 USA
*/ */
package org.hibernate.dialect.lock; package org.hibernate.dialect.lock;
import java.io.Serializable; import java.io.Serializable;
import org.hibernate.HibernateException; import org.hibernate.HibernateException;
import org.hibernate.JDBCException;
import org.hibernate.LockMode; import org.hibernate.LockMode;
import org.hibernate.StaleObjectStateException;
import org.hibernate.engine.spi.EntityEntry; import org.hibernate.engine.spi.EntityEntry;
import org.hibernate.engine.spi.SessionImplementor; import org.hibernate.engine.spi.SessionImplementor;
import org.hibernate.persister.entity.EntityPersister; import org.hibernate.persister.entity.EntityPersister;
@ -60,15 +59,8 @@ public class PessimisticForceIncrementLockingStrategy implements LockingStrategy
} }
} }
/** @Override
* {@inheritDoc} public void lock(Serializable id, Object version, Object object, int timeout, SessionImplementor session) {
*/
public void lock(
Serializable id,
Object version,
Object object,
int timeout,
SessionImplementor session) throws StaleObjectStateException, JDBCException {
if ( !lockable.isVersioned() ) { if ( !lockable.isVersioned() ) {
throw new HibernateException( "[" + lockMode + "] not supported for non-versioned entities [" + lockable.getEntityName() + "]" ); throw new HibernateException( "[" + lockMode + "] not supported for non-versioned entities [" + lockable.getEntityName() + "]" );
} }

View File

@ -22,6 +22,7 @@
* Boston, MA 02110-1301 USA * Boston, MA 02110-1301 USA
*/ */
package org.hibernate.dialect.lock; package org.hibernate.dialect.lock;
import java.io.Serializable; import java.io.Serializable;
import java.sql.PreparedStatement; import java.sql.PreparedStatement;
import java.sql.ResultSet; import java.sql.ResultSet;
@ -50,8 +51,10 @@ import org.hibernate.sql.SimpleSelect;
* *
* @author Steve Ebersole * @author Steve Ebersole
* @author Scott Marlow * @author Scott Marlow
*
* @see org.hibernate.dialect.Dialect#getForUpdateString(org.hibernate.LockMode) * @see org.hibernate.dialect.Dialect#getForUpdateString(org.hibernate.LockMode)
* @see org.hibernate.dialect.Dialect#appendLockHint(org.hibernate.LockMode, String) * @see org.hibernate.dialect.Dialect#appendLockHint(org.hibernate.LockMode, String)
*
* @since 3.5 * @since 3.5
*/ */
public class PessimisticReadSelectLockingStrategy extends AbstractSelectLockingStrategy { public class PessimisticReadSelectLockingStrategy extends AbstractSelectLockingStrategy {
@ -65,56 +68,53 @@ public class PessimisticReadSelectLockingStrategy extends AbstractSelectLockingS
super( lockable, lockMode ); super( lockable, lockMode );
} }
/** @Override
* @see org.hibernate.dialect.lock.LockingStrategy#lock public void lock(Serializable id, Object version, Object object, int timeout, SessionImplementor session) {
*/
public void lock(
Serializable id,
Object version,
Object object,
int timeout,
SessionImplementor session) throws StaleObjectStateException, JDBCException {
final String sql = determineSql( timeout ); final String sql = determineSql( timeout );
SessionFactoryImplementor factory = session.getFactory(); SessionFactoryImplementor factory = session.getFactory();
try { try {
PreparedStatement st = session.getTransactionCoordinator().getJdbcCoordinator().getStatementPreparer().prepareStatement( sql );
try { try {
getLockable().getIdentifierType().nullSafeSet( st, id, 1, session ); PreparedStatement st = session.getTransactionCoordinator().getJdbcCoordinator().getStatementPreparer().prepareStatement( sql );
if ( getLockable().isVersioned() ) {
getLockable().getVersionType().nullSafeSet(
st,
version,
getLockable().getIdentifierType().getColumnSpan( factory ) + 1,
session
);
}
ResultSet rs = st.executeQuery();
try { try {
if ( !rs.next() ) { getLockable().getIdentifierType().nullSafeSet( st, id, 1, session );
if ( factory.getStatistics().isStatisticsEnabled() ) { if ( getLockable().isVersioned() ) {
factory.getStatisticsImplementor() getLockable().getVersionType().nullSafeSet(
.optimisticFailure( getLockable().getEntityName() ); st,
version,
getLockable().getIdentifierType().getColumnSpan( factory ) + 1,
session
);
}
ResultSet rs = st.executeQuery();
try {
if ( !rs.next() ) {
if ( factory.getStatistics().isStatisticsEnabled() ) {
factory.getStatisticsImplementor()
.optimisticFailure( getLockable().getEntityName() );
}
throw new StaleObjectStateException( getLockable().getEntityName(), id );
} }
throw new StaleObjectStateException( getLockable().getEntityName(), id ); }
finally {
rs.close();
} }
} }
finally { finally {
rs.close(); st.close();
} }
}
finally {
st.close();
}
}
catch ( SQLException e ) {
throw session.getFactory().getSQLExceptionHelper().convert(
e,
"could not lock: " + MessageHelper.infoString( getLockable(), id, session.getFactory() ),
sql
);
}
} }
catch ( SQLException sqle ) { catch (JDBCException e) {
JDBCException e = session.getFactory().getSQLExceptionHelper().convert( throw new PessimisticEntityLockException( object, "could not obtain pessimistic lock", e );
sqle,
"could not lock: " + MessageHelper.infoString( getLockable(), id, session.getFactory() ),
sql
);
throw new PessimisticLockException( "could not obtain pessimistic lock", e, object );
} }
} }

View File

@ -22,6 +22,7 @@
* Boston, MA 02110-1301 USA * Boston, MA 02110-1301 USA
*/ */
package org.hibernate.dialect.lock; package org.hibernate.dialect.lock;
import java.io.Serializable; import java.io.Serializable;
import java.sql.PreparedStatement; import java.sql.PreparedStatement;
import java.sql.SQLException; import java.sql.SQLException;
@ -47,15 +48,16 @@ import org.hibernate.sql.Update;
* *
* This class is a clone of UpdateLockingStrategy. * This class is a clone of UpdateLockingStrategy.
* *
* @since 3.5
*
* @author Steve Ebersole * @author Steve Ebersole
* @author Scott Marlow * @author Scott Marlow
* @since 3.5
*/ */
public class PessimisticReadUpdateLockingStrategy implements LockingStrategy { public class PessimisticReadUpdateLockingStrategy implements LockingStrategy {
private static final CoreMessageLogger LOG = Logger.getMessageLogger(CoreMessageLogger.class, private static final CoreMessageLogger LOG = Logger.getMessageLogger(
PessimisticReadUpdateLockingStrategy.class.getName()); CoreMessageLogger.class,
PessimisticReadUpdateLockingStrategy.class.getName()
);
private final Lockable lockable; private final Lockable lockable;
private final LockMode lockMode; private final LockMode lockMode;
@ -65,7 +67,7 @@ public class PessimisticReadUpdateLockingStrategy implements LockingStrategy {
* Construct a locking strategy based on SQL UPDATE statements. * Construct a locking strategy based on SQL UPDATE statements.
* *
* @param lockable The metadata for the entity to be locked. * @param lockable The metadata for the entity to be locked.
* @param lockMode Indictates the type of lock to be acquired. Note that * @param lockMode Indicates the type of lock to be acquired. Note that
* read-locks are not valid for this strategy. * read-locks are not valid for this strategy.
*/ */
public PessimisticReadUpdateLockingStrategy(Lockable lockable, LockMode lockMode) { public PessimisticReadUpdateLockingStrategy(Lockable lockable, LockMode lockMode) {
@ -83,50 +85,48 @@ public class PessimisticReadUpdateLockingStrategy implements LockingStrategy {
} }
} }
/** @Override
* @see org.hibernate.dialect.lock.LockingStrategy#lock public void lock(Serializable id, Object version, Object object, int timeout, SessionImplementor session) {
*/
public void lock(
Serializable id,
Object version,
Object object,
int timeout, SessionImplementor session) throws StaleObjectStateException, JDBCException {
if ( !lockable.isVersioned() ) { if ( !lockable.isVersioned() ) {
throw new HibernateException( "write locks via update not supported for non-versioned entities [" + lockable.getEntityName() + "]" ); throw new HibernateException( "write locks via update not supported for non-versioned entities [" + lockable.getEntityName() + "]" );
} }
SessionFactoryImplementor factory = session.getFactory(); SessionFactoryImplementor factory = session.getFactory();
try { try {
PreparedStatement st = session.getTransactionCoordinator().getJdbcCoordinator().getStatementPreparer().prepareStatement( sql );
try { try {
lockable.getVersionType().nullSafeSet( st, version, 1, session ); PreparedStatement st = session.getTransactionCoordinator().getJdbcCoordinator().getStatementPreparer().prepareStatement( sql );
int offset = 2; try {
lockable.getVersionType().nullSafeSet( st, version, 1, session );
int offset = 2;
lockable.getIdentifierType().nullSafeSet( st, id, offset, session ); lockable.getIdentifierType().nullSafeSet( st, id, offset, session );
offset += lockable.getIdentifierType().getColumnSpan( factory ); offset += lockable.getIdentifierType().getColumnSpan( factory );
if ( lockable.isVersioned() ) {
lockable.getVersionType().nullSafeSet( st, version, offset, session );
}
int affected = st.executeUpdate();
if ( affected < 0 ) { // todo: should this instead check for exactly one row modified?
factory.getStatisticsImplementor().optimisticFailure( lockable.getEntityName() );
throw new StaleObjectStateException( lockable.getEntityName(), id );
}
if ( lockable.isVersioned() ) {
lockable.getVersionType().nullSafeSet( st, version, offset, session );
} }
finally {
int affected = st.executeUpdate(); st.close();
if ( affected < 0 ) { // todo: should this instead check for exactly one row modified?
factory.getStatisticsImplementor().optimisticFailure( lockable.getEntityName() );
throw new StaleObjectStateException( lockable.getEntityName(), id );
} }
} }
finally { catch ( SQLException e ) {
st.close(); throw session.getFactory().getSQLExceptionHelper().convert(
} e,
"could not lock: " + MessageHelper.infoString( lockable, id, session.getFactory() ),
} sql
catch ( SQLException sqle ) {
JDBCException e = session.getFactory().getSQLExceptionHelper().convert(
sqle,
"could not lock: " + MessageHelper.infoString( lockable, id, session.getFactory() ),
sql
); );
throw new PessimisticLockException("could not obtain pessimistic lock", e, object); }
}
catch (JDBCException e) {
throw new PessimisticEntityLockException( object, "could not obtain pessimistic lock", e );
} }
} }

View File

@ -22,6 +22,7 @@
* Boston, MA 02110-1301 USA * Boston, MA 02110-1301 USA
*/ */
package org.hibernate.dialect.lock; package org.hibernate.dialect.lock;
import java.io.Serializable; import java.io.Serializable;
import java.sql.PreparedStatement; import java.sql.PreparedStatement;
import java.sql.ResultSet; import java.sql.ResultSet;
@ -48,10 +49,11 @@ import org.hibernate.sql.SimpleSelect;
* *
* This class is a clone of SelectLockingStrategy. * This class is a clone of SelectLockingStrategy.
* *
* @author Steve Ebersole
* @author Scott Marlow
* @see org.hibernate.dialect.Dialect#getForUpdateString(org.hibernate.LockMode) * @see org.hibernate.dialect.Dialect#getForUpdateString(org.hibernate.LockMode)
* @see org.hibernate.dialect.Dialect#appendLockHint(org.hibernate.LockMode, String) * @see org.hibernate.dialect.Dialect#appendLockHint(org.hibernate.LockMode, String)
*
* @author Steve Ebersole
* @author Scott Marlow
* @since 3.5 * @since 3.5
*/ */
public class PessimisticWriteSelectLockingStrategy extends AbstractSelectLockingStrategy { public class PessimisticWriteSelectLockingStrategy extends AbstractSelectLockingStrategy {
@ -65,56 +67,52 @@ public class PessimisticWriteSelectLockingStrategy extends AbstractSelectLocking
super( lockable, lockMode ); super( lockable, lockMode );
} }
/** @Override
* @see LockingStrategy#lock public void lock(Serializable id, Object version, Object object, int timeout, SessionImplementor session) {
*/
public void lock(
Serializable id,
Object version,
Object object,
int timeout,
SessionImplementor session) throws StaleObjectStateException, JDBCException {
final String sql = determineSql( timeout ); final String sql = determineSql( timeout );
SessionFactoryImplementor factory = session.getFactory(); SessionFactoryImplementor factory = session.getFactory();
try { try {
PreparedStatement st = session.getTransactionCoordinator().getJdbcCoordinator().getStatementPreparer().prepareStatement( sql );
try { try {
getLockable().getIdentifierType().nullSafeSet( st, id, 1, session ); PreparedStatement st = session.getTransactionCoordinator().getJdbcCoordinator().getStatementPreparer().prepareStatement( sql );
if ( getLockable().isVersioned() ) {
getLockable().getVersionType().nullSafeSet(
st,
version,
getLockable().getIdentifierType().getColumnSpan( factory ) + 1,
session
);
}
ResultSet rs = st.executeQuery();
try { try {
if ( !rs.next() ) { getLockable().getIdentifierType().nullSafeSet( st, id, 1, session );
if ( factory.getStatistics().isStatisticsEnabled() ) { if ( getLockable().isVersioned() ) {
factory.getStatisticsImplementor() getLockable().getVersionType().nullSafeSet(
.optimisticFailure( getLockable().getEntityName() ); st,
version,
getLockable().getIdentifierType().getColumnSpan( factory ) + 1,
session
);
}
ResultSet rs = st.executeQuery();
try {
if ( !rs.next() ) {
if ( factory.getStatistics().isStatisticsEnabled() ) {
factory.getStatisticsImplementor()
.optimisticFailure( getLockable().getEntityName() );
}
throw new StaleObjectStateException( getLockable().getEntityName(), id );
} }
throw new StaleObjectStateException( getLockable().getEntityName(), id ); }
finally {
rs.close();
} }
} }
finally { finally {
rs.close(); st.close();
} }
} }
finally { catch ( SQLException e ) {
st.close(); throw session.getFactory().getSQLExceptionHelper().convert(
e,
"could not lock: " + MessageHelper.infoString( getLockable(), id, session.getFactory() ),
sql
);
} }
} }
catch ( SQLException sqle ) { catch (JDBCException e) {
JDBCException e = session.getFactory().getSQLExceptionHelper().convert( throw new PessimisticEntityLockException( object, "could not obtain pessimistic lock", e );
sqle,
"could not lock: " + MessageHelper.infoString( getLockable(), id, session.getFactory() ),
sql
);
throw new PessimisticLockException( "could not obtain pessimistic lock", e, object );
} }
} }

View File

@ -22,6 +22,7 @@
* Boston, MA 02110-1301 USA * Boston, MA 02110-1301 USA
*/ */
package org.hibernate.dialect.lock; package org.hibernate.dialect.lock;
import java.io.Serializable; import java.io.Serializable;
import java.sql.PreparedStatement; import java.sql.PreparedStatement;
import java.sql.SQLException; import java.sql.SQLException;
@ -47,15 +48,16 @@ import org.hibernate.sql.Update;
* *
* This class is a clone of UpdateLockingStrategy. * This class is a clone of UpdateLockingStrategy.
* *
* @since 3.5
*
* @author Steve Ebersole * @author Steve Ebersole
* @author Scott Marlow * @author Scott Marlow
* @since 3.5
*/ */
public class PessimisticWriteUpdateLockingStrategy implements LockingStrategy { public class PessimisticWriteUpdateLockingStrategy implements LockingStrategy {
private static final CoreMessageLogger LOG = Logger.getMessageLogger(CoreMessageLogger.class, private static final CoreMessageLogger LOG = Logger.getMessageLogger(
PessimisticWriteUpdateLockingStrategy.class.getName()); CoreMessageLogger.class,
PessimisticWriteUpdateLockingStrategy.class.getName()
);
private final Lockable lockable; private final Lockable lockable;
private final LockMode lockMode; private final LockMode lockMode;
@ -65,8 +67,7 @@ public class PessimisticWriteUpdateLockingStrategy implements LockingStrategy {
* Construct a locking strategy based on SQL UPDATE statements. * Construct a locking strategy based on SQL UPDATE statements.
* *
* @param lockable The metadata for the entity to be locked. * @param lockable The metadata for the entity to be locked.
* @param lockMode Indictates the type of lock to be acquired. Note that * @param lockMode Indicates the type of lock to be acquired. Note that read-locks are not valid for this strategy.
* read-locks are not valid for this strategy.
*/ */
public PessimisticWriteUpdateLockingStrategy(Lockable lockable, LockMode lockMode) { public PessimisticWriteUpdateLockingStrategy(Lockable lockable, LockMode lockMode) {
this.lockable = lockable; this.lockable = lockable;
@ -83,50 +84,47 @@ public class PessimisticWriteUpdateLockingStrategy implements LockingStrategy {
} }
} }
/** @Override
* @see LockingStrategy#lock public void lock(Serializable id, Object version, Object object, int timeout, SessionImplementor session) {
*/
public void lock(
Serializable id,
Object version,
Object object,
int timeout, SessionImplementor session) throws StaleObjectStateException, JDBCException {
if ( !lockable.isVersioned() ) { if ( !lockable.isVersioned() ) {
throw new HibernateException( "write locks via update not supported for non-versioned entities [" + lockable.getEntityName() + "]" ); throw new HibernateException( "write locks via update not supported for non-versioned entities [" + lockable.getEntityName() + "]" );
} }
SessionFactoryImplementor factory = session.getFactory(); SessionFactoryImplementor factory = session.getFactory();
try { try {
PreparedStatement st = session.getTransactionCoordinator().getJdbcCoordinator().getStatementPreparer().prepareStatement( sql );
try { try {
lockable.getVersionType().nullSafeSet( st, version, 1, session ); PreparedStatement st = session.getTransactionCoordinator().getJdbcCoordinator().getStatementPreparer().prepareStatement( sql );
int offset = 2; try {
lockable.getVersionType().nullSafeSet( st, version, 1, session );
int offset = 2;
lockable.getIdentifierType().nullSafeSet( st, id, offset, session ); lockable.getIdentifierType().nullSafeSet( st, id, offset, session );
offset += lockable.getIdentifierType().getColumnSpan( factory ); offset += lockable.getIdentifierType().getColumnSpan( factory );
if ( lockable.isVersioned() ) {
lockable.getVersionType().nullSafeSet( st, version, offset, session );
}
int affected = st.executeUpdate();
if ( affected < 0 ) { // todo: should this instead check for exactly one row modified?
factory.getStatisticsImplementor().optimisticFailure( lockable.getEntityName() );
throw new StaleObjectStateException( lockable.getEntityName(), id );
}
if ( lockable.isVersioned() ) {
lockable.getVersionType().nullSafeSet( st, version, offset, session );
} }
finally {
int affected = st.executeUpdate(); st.close();
if ( affected < 0 ) { // todo: should this instead check for exactly one row modified?
factory.getStatisticsImplementor().optimisticFailure( lockable.getEntityName() );
throw new StaleObjectStateException( lockable.getEntityName(), id );
} }
} }
finally { catch ( SQLException e ) {
st.close(); throw session.getFactory().getSQLExceptionHelper().convert(
} e,
"could not lock: " + MessageHelper.infoString( lockable, id, session.getFactory() ),
} sql
catch ( SQLException sqle ) {
JDBCException e = session.getFactory().getSQLExceptionHelper().convert(
sqle,
"could not lock: " + MessageHelper.infoString( lockable, id, session.getFactory() ),
sql
); );
throw new PessimisticLockException("could not obtain pessimistic lock", e, object); }
}
catch (JDBCException e) {
throw new PessimisticEntityLockException( object, "could not obtain pessimistic lock", e );
} }
} }

View File

@ -22,6 +22,7 @@
* Boston, MA 02110-1301 USA * Boston, MA 02110-1301 USA
*/ */
package org.hibernate.dialect.lock; package org.hibernate.dialect.lock;
import java.io.Serializable; import java.io.Serializable;
import java.sql.PreparedStatement; import java.sql.PreparedStatement;
import java.sql.ResultSet; import java.sql.ResultSet;
@ -45,9 +46,9 @@ import org.hibernate.sql.SimpleSelect;
* *
* @see org.hibernate.dialect.Dialect#getForUpdateString(org.hibernate.LockMode) * @see org.hibernate.dialect.Dialect#getForUpdateString(org.hibernate.LockMode)
* @see org.hibernate.dialect.Dialect#appendLockHint(org.hibernate.LockMode, String) * @see org.hibernate.dialect.Dialect#appendLockHint(org.hibernate.LockMode, String)
* @since 3.2
* *
* @author Steve Ebersole * @author Steve Ebersole
* @since 3.2
*/ */
public class SelectLockingStrategy extends AbstractSelectLockingStrategy { public class SelectLockingStrategy extends AbstractSelectLockingStrategy {
/** /**

View File

@ -22,6 +22,7 @@
* Boston, MA 02110-1301 USA * Boston, MA 02110-1301 USA
*/ */
package org.hibernate.dialect.lock; package org.hibernate.dialect.lock;
import java.io.Serializable; import java.io.Serializable;
import java.sql.PreparedStatement; import java.sql.PreparedStatement;
import java.sql.SQLException; import java.sql.SQLException;
@ -44,13 +45,15 @@ import org.hibernate.sql.Update;
* <p/> * <p/>
* This strategy is not valid for read style locks. * This strategy is not valid for read style locks.
* *
* @since 3.2
*
* @author Steve Ebersole * @author Steve Ebersole
* @since 3.2
*/ */
public class UpdateLockingStrategy implements LockingStrategy { public class UpdateLockingStrategy implements LockingStrategy {
private static final CoreMessageLogger LOG = Logger.getMessageLogger(CoreMessageLogger.class, UpdateLockingStrategy.class.getName()); private static final CoreMessageLogger LOG = Logger.getMessageLogger(
CoreMessageLogger.class,
UpdateLockingStrategy.class.getName()
);
private final Lockable lockable; private final Lockable lockable;
private final LockMode lockMode; private final LockMode lockMode;
@ -78,9 +81,7 @@ public class UpdateLockingStrategy implements LockingStrategy {
} }
} }
/** @Override
* @see LockingStrategy#lock
*/
public void lock( public void lock(
Serializable id, Serializable id,
Object version, Object version,

View File

@ -83,6 +83,9 @@ import org.hibernate.TransientObjectException;
import org.hibernate.TypeMismatchException; import org.hibernate.TypeMismatchException;
import org.hibernate.UnresolvableObjectException; import org.hibernate.UnresolvableObjectException;
import org.hibernate.cfg.Environment; import org.hibernate.cfg.Environment;
import org.hibernate.dialect.lock.LockingStrategyException;
import org.hibernate.dialect.lock.OptimisticEntityLockException;
import org.hibernate.dialect.lock.PessimisticEntityLockException;
import org.hibernate.ejb.criteria.CriteriaQueryCompiler; import org.hibernate.ejb.criteria.CriteriaQueryCompiler;
import org.hibernate.ejb.criteria.ValueHandlerFactory; import org.hibernate.ejb.criteria.ValueHandlerFactory;
import org.hibernate.ejb.criteria.expression.CompoundSelectionImpl; import org.hibernate.ejb.criteria.expression.CompoundSelectionImpl;
@ -1301,7 +1304,7 @@ public abstract class AbstractEntityManagerImpl implements HibernateEntityManage
handlePersistenceException( converted ); handlePersistenceException( converted );
return converted; return converted;
} }
else if ( e instanceof org.hibernate.OptimisticLockException ) { else if ( e instanceof LockingStrategyException ) {
PersistenceException converted = wrapLockException( e, lockOptions ); PersistenceException converted = wrapLockException( e, lockOptions );
handlePersistenceException( converted ); handlePersistenceException( converted );
return converted; return converted;
@ -1397,19 +1400,29 @@ public abstract class AbstractEntityManagerImpl implements HibernateEntityManage
} }
public PersistenceException wrapLockException(HibernateException e, LockOptions lockOptions) { public PersistenceException wrapLockException(HibernateException e, LockOptions lockOptions) {
PersistenceException pe; final PersistenceException pe;
if ( e instanceof org.hibernate.OptimisticLockException ) { if ( e instanceof OptimisticEntityLockException ) {
org.hibernate.OptimisticLockException ole = ( org.hibernate.OptimisticLockException ) e; final OptimisticEntityLockException lockException = (OptimisticEntityLockException) e;
pe = new OptimisticLockException( ole.getMessage(), ole, ole.getEntity() ); pe = new OptimisticLockException( lockException.getMessage(), lockException, lockException.getEntity() );
} }
else if ( e instanceof org.hibernate.PessimisticLockException ) { else if ( e instanceof PessimisticEntityLockException ) {
org.hibernate.PessimisticLockException ple = ( org.hibernate.PessimisticLockException ) e; PessimisticEntityLockException lockException = (PessimisticEntityLockException) e;
if ( lockOptions != null && lockOptions.getTimeOut() > -1 ) { if ( lockOptions != null && lockOptions.getTimeOut() > -1 ) {
// assume lock timeout occurred if a timeout or NO WAIT was specified // assume lock timeout occurred if a timeout or NO WAIT was specified
pe = new LockTimeoutException( ple.getMessage(), ple, ple.getEntity() ); pe = new LockTimeoutException( lockException.getMessage(), lockException, lockException.getEntity() );
} }
else { else {
pe = new PessimisticLockException( ple.getMessage(), ple, ple.getEntity() ); pe = new PessimisticLockException( lockException.getMessage(), lockException, lockException.getEntity() );
}
}
else if ( e instanceof org.hibernate.PessimisticLockException ) {
org.hibernate.PessimisticLockException jdbcLockException = ( org.hibernate.PessimisticLockException ) e;
if ( lockOptions != null && lockOptions.getTimeOut() > -1 ) {
// assume lock timeout occurred if a timeout or NO WAIT was specified
pe = new LockTimeoutException( jdbcLockException.getMessage(), jdbcLockException, null );
}
else {
pe = new PessimisticLockException( jdbcLockException.getMessage(), jdbcLockException, null );
} }
} }
else { else {