HHH-1168 - Problem combining locking and paging on Oracle

This commit is contained in:
Steve Ebersole 2012-11-29 12:33:54 -06:00
parent 5707798b4b
commit 6e71a0907e
6 changed files with 38 additions and 69 deletions

View File

@ -2400,7 +2400,7 @@ public abstract class Dialect implements ConversionContext {
return false;
}
public boolean supportsLockingAndPaging() {
return true;
public boolean useFollowOnLocking() {
return false;
}
}

View File

@ -578,7 +578,7 @@ public class Oracle8iDialect extends Dialect {
}
@Override
public boolean supportsLockingAndPaging() {
return false;
public boolean useFollowOnLocking() {
return true;
}
}

View File

@ -1586,9 +1586,9 @@ public interface CoreMessageLogger extends BasicLogger {
@LogMessage(level = WARN)
@Message(
value = "Encountered request which combined locking and paging, however dialect reports that database does " +
"not support that combination. Results will be locked after initial query executes",
value = "Encountered request for locking however dialect reports that database prefers locking be done in a " +
"separate select; results will be locked after initial query executes",
id = 444
)
void delayedLockingDueToPaging();
void usingFollowOnLocking();
}

View File

@ -249,30 +249,23 @@ public abstract class Loader {
public void afterLoad(SessionImplementor session, Object entity, Loadable persister);
}
protected boolean shouldDelayLockingDueToPaging(
String sql,
protected boolean shouldUseFollowOnLocking(
QueryParameters parameters,
Dialect dialect,
List<AfterLoadAction> afterLoadActions) {
final LockOptions lockOptions = parameters.getLockOptions();
final RowSelection rowSelection = parameters.getRowSelection();
final LimitHandler limitHandler = dialect.buildLimitHandler( sql, rowSelection );
if ( LimitHelper.useLimit( limitHandler, rowSelection ) ) {
// user has requested a combination of paging and locking. See if the dialect supports that
// (ahem, Oracle...)
if ( ! dialect.supportsLockingAndPaging() ) {
LOG.delayedLockingDueToPaging();
afterLoadActions.add(
new AfterLoadAction() {
private final LockOptions originalLockOptions = lockOptions.makeCopy();
@Override
public void afterLoad(SessionImplementor session, Object entity, Loadable persister) {
( (Session) session ).buildLockRequest( originalLockOptions ).lock( persister.getEntityName(), entity );
}
if ( dialect.useFollowOnLocking() ) {
LOG.usingFollowOnLocking();
final LockOptions lockOptions = parameters.getLockOptions();
afterLoadActions.add(
new AfterLoadAction() {
private final LockOptions originalLockOptions = lockOptions.makeCopy();
@Override
public void afterLoad(SessionImplementor session, Object entity, Loadable persister) {
( (Session) session ).buildLockRequest( originalLockOptions ).lock( persister.getEntityName(), entity );
}
);
parameters.setLockOptions( new LockOptions() );
}
}
);
parameters.setLockOptions( new LockOptions() );
return true;
}
return false;

View File

@ -38,11 +38,8 @@ import org.hibernate.ScrollMode;
import org.hibernate.ScrollableResults;
import org.hibernate.Session;
import org.hibernate.dialect.Dialect;
import org.hibernate.dialect.pagination.LimitHandler;
import org.hibernate.dialect.pagination.LimitHelper;
import org.hibernate.engine.spi.LoadQueryInfluencers;
import org.hibernate.engine.spi.QueryParameters;
import org.hibernate.engine.spi.RowSelection;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.engine.spi.SessionImplementor;
import org.hibernate.internal.CriteriaImpl;
@ -207,43 +204,27 @@ public class CriteriaLoader extends OuterJoinLoader {
return sql;
}
// user is request locking, lets see if we can apply locking directly to the SQL...
if ( dialect.useFollowOnLocking() ) {
// Dialect prefers to perform locking in a separate step
LOG.usingFollowOnLocking();
final LockOptions lockOptionsToUse = new LockOptions();
lockOptionsToUse.setLockMode( lockOptions.getEffectiveLockMode( "this_" ) );
lockOptionsToUse.setTimeOut( lockOptions.getTimeOut() );
lockOptionsToUse.setScope( lockOptions.getScope() );
// some dialects wont allow locking with paging...
final RowSelection rowSelection = parameters.getRowSelection();
final LimitHandler limitHandler = dialect.buildLimitHandler( sql, rowSelection );
if ( LimitHelper.useLimit( limitHandler, rowSelection ) ) {
// user has requested a combination of paging and locking. See if the dialect supports that
// (ahem, Oracle...)
if ( ! dialect.supportsLockingAndPaging() ) {
LOG.delayedLockingDueToPaging();
// this one is kind of ugly. currently we do not track the needed alias-to-entity
// mapping into the "hydratedEntities" which drives these callbacks
// so for now apply the root lock mode to all. The root lock mode is listed in
// the alias specific map under the alias "this_"...
final LockOptions lockOptionsToUse = new LockOptions();
lockOptionsToUse.setLockMode( lockOptions.getEffectiveLockMode( "this_" ) );
lockOptionsToUse.setTimeOut( lockOptions.getTimeOut() );
lockOptionsToUse.setScope( lockOptions.getScope() );
afterLoadActions.add(
new AfterLoadAction() {
@Override
public void afterLoad(SessionImplementor session, Object entity, Loadable persister) {
( (Session) session ).buildLockRequest( lockOptionsToUse )
.lock( persister.getEntityName(), entity );
}
afterLoadActions.add(
new AfterLoadAction() {
@Override
public void afterLoad(SessionImplementor session, Object entity, Loadable persister) {
( (Session) session ).buildLockRequest( lockOptionsToUse )
.lock( persister.getEntityName(), entity );
}
);
parameters.setLockOptions( new LockOptions() );
return sql;
}
}
);
parameters.setLockOptions( new LockOptions() );
return sql;
}
// there are other conditions we might want to add here, such as checking the result types etc
// but those are better served after we have redone the SQL generation to use ASTs.
final LockOptions locks = new LockOptions(lockOptions.getLockMode());
locks.setScope( lockOptions.getScope());
locks.setTimeOut( lockOptions.getTimeOut());

View File

@ -23,7 +23,6 @@
*/
package org.hibernate.loader.hql;
import java.io.Serializable;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
@ -39,12 +38,8 @@ import org.hibernate.LockMode;
import org.hibernate.LockOptions;
import org.hibernate.QueryException;
import org.hibernate.ScrollableResults;
import org.hibernate.Session;
import org.hibernate.dialect.Dialect;
import org.hibernate.dialect.pagination.LimitHandler;
import org.hibernate.dialect.pagination.LimitHelper;
import org.hibernate.engine.spi.QueryParameters;
import org.hibernate.engine.spi.RowSelection;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.engine.spi.SessionImplementor;
import org.hibernate.event.spi.EventSource;
@ -334,7 +329,7 @@ public class QueryLoader extends BasicLoader {
// user is request locking, lets see if we can apply locking directly to the SQL...
// some dialects wont allow locking with paging...
if ( shouldDelayLockingDueToPaging( sql, parameters, dialect, afterLoadActions ) ) {
if ( shouldUseFollowOnLocking( parameters, dialect, afterLoadActions ) ) {
return sql;
}