HHH-1168 - Problem combining locking and paging on Oracle
This commit is contained in:
parent
c01dd40a65
commit
4b2871cfba
|
@ -2399,4 +2399,8 @@ public abstract class Dialect implements ConversionContext {
|
||||||
public boolean forceLobAsLastValue() {
|
public boolean forceLobAsLastValue() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean supportsLockingAndPaging() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -577,4 +577,8 @@ public class Oracle8iDialect extends Dialect {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean supportsLockingAndPaging() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -953,7 +953,8 @@ public class QueryTranslatorImpl extends BasicLoader implements FilterTranslator
|
||||||
if ( stats ) startTime = System.currentTimeMillis();
|
if ( stats ) startTime = System.currentTimeMillis();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
final ResultSet rs = executeQueryStatement( queryParameters, false, session );
|
final List<AfterLoadAction> afterLoadActions = new ArrayList<AfterLoadAction>();
|
||||||
|
final ResultSet rs = executeQueryStatement( queryParameters, false, afterLoadActions, session );
|
||||||
final PreparedStatement st = (PreparedStatement) rs.getStatement();
|
final PreparedStatement st = (PreparedStatement) rs.getStatement();
|
||||||
HolderInstantiator hi = HolderInstantiator.createClassicHolderInstantiator(holderConstructor, queryParameters.getResultTransformer());
|
HolderInstantiator hi = HolderInstantiator.createClassicHolderInstantiator(holderConstructor, queryParameters.getResultTransformer());
|
||||||
Iterator result = new IteratorImpl( rs, st, session, queryParameters.isReadOnly( session ), returnTypes, getColumnNames(), hi );
|
Iterator result = new IteratorImpl( rs, st, session, queryParameters.isReadOnly( session ), returnTypes, getColumnNames(), hi );
|
||||||
|
@ -1094,8 +1095,13 @@ public class QueryTranslatorImpl extends BasicLoader implements FilterTranslator
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected String applyLocks(String sql, LockOptions lockOptions, Dialect dialect) throws QueryException {
|
protected String applyLocks(
|
||||||
|
String sql,
|
||||||
|
QueryParameters parameters,
|
||||||
|
Dialect dialect,
|
||||||
|
List<AfterLoadAction> afterLoadActions) throws QueryException {
|
||||||
// can't cache this stuff either (per-invocation)
|
// can't cache this stuff either (per-invocation)
|
||||||
|
final LockOptions lockOptions = parameters.getLockOptions();
|
||||||
final String result;
|
final String result;
|
||||||
if ( lockOptions == null ||
|
if ( lockOptions == null ||
|
||||||
( lockOptions.getLockMode() == LockMode.NONE && lockOptions.getAliasLockCount() == 0 ) ) {
|
( lockOptions.getLockMode() == LockMode.NONE && lockOptions.getAliasLockCount() == 0 ) ) {
|
||||||
|
|
|
@ -1583,4 +1583,12 @@ public interface CoreMessageLogger extends BasicLogger {
|
||||||
id = 443
|
id = 443
|
||||||
)
|
)
|
||||||
void tooManyInExpressions(String dialectName, int limit, String paramName, int size);
|
void tooManyInExpressions(String dialectName, int limit, String paramName, int size);
|
||||||
|
|
||||||
|
@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",
|
||||||
|
id = 444
|
||||||
|
)
|
||||||
|
void delayedLockingDueToPaging();
|
||||||
}
|
}
|
||||||
|
|
|
@ -68,6 +68,7 @@ public class SQLQueryImpl extends AbstractQueryImpl implements SQLQuery {
|
||||||
private Collection<String> querySpaces;
|
private Collection<String> querySpaces;
|
||||||
|
|
||||||
private final boolean callable;
|
private final boolean callable;
|
||||||
|
private final LockOptions lockOptions = new LockOptions();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs a SQLQueryImpl given a sql query defined in the mappings.
|
* Constructs a SQLQueryImpl given a sql query defined in the mappings.
|
||||||
|
@ -245,8 +246,8 @@ public class SQLQueryImpl extends AbstractQueryImpl implements SQLQuery {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public LockOptions getLockOptions() {
|
public LockOptions getLockOptions() {
|
||||||
//we never need to apply locks to the SQL
|
//we never need to apply locks to the SQL, however the native-sql loader handles this specially
|
||||||
return null;
|
return lockOptions;
|
||||||
}
|
}
|
||||||
|
|
||||||
public SQLQuery addScalar(final String columnAlias, final Type type) {
|
public SQLQuery addScalar(final String columnAlias, final Type type) {
|
||||||
|
|
|
@ -26,6 +26,7 @@ package org.hibernate.internal;
|
||||||
import java.sql.CallableStatement;
|
import java.sql.CallableStatement;
|
||||||
import java.sql.ResultSet;
|
import java.sql.ResultSet;
|
||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
@ -299,6 +300,8 @@ public class StoredProcedureOutputsImpl implements StoredProcedureOutputs {
|
||||||
this.session = session;
|
this.session = session;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// todo : this would be a great way to add locking to stored procedure support (at least where returning entities).
|
||||||
|
|
||||||
public List processResultSet(ResultSet resultSet) throws SQLException {
|
public List processResultSet(ResultSet resultSet) throws SQLException {
|
||||||
super.autoDiscoverTypes( resultSet );
|
super.autoDiscoverTypes( resultSet );
|
||||||
return super.processResultSet(
|
return super.processResultSet(
|
||||||
|
@ -307,7 +310,8 @@ public class StoredProcedureOutputsImpl implements StoredProcedureOutputs {
|
||||||
session,
|
session,
|
||||||
true,
|
true,
|
||||||
null,
|
null,
|
||||||
Integer.MAX_VALUE
|
Integer.MAX_VALUE,
|
||||||
|
Collections.<AfterLoadAction>emptyList()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,6 +31,7 @@ import java.sql.SQLException;
|
||||||
import java.sql.Statement;
|
import java.sql.Statement;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
|
@ -47,6 +48,7 @@ import org.hibernate.LockOptions;
|
||||||
import org.hibernate.QueryException;
|
import org.hibernate.QueryException;
|
||||||
import org.hibernate.ScrollMode;
|
import org.hibernate.ScrollMode;
|
||||||
import org.hibernate.ScrollableResults;
|
import org.hibernate.ScrollableResults;
|
||||||
|
import org.hibernate.Session;
|
||||||
import org.hibernate.StaleObjectStateException;
|
import org.hibernate.StaleObjectStateException;
|
||||||
import org.hibernate.WrongClassException;
|
import org.hibernate.WrongClassException;
|
||||||
import org.hibernate.cache.spi.FilterKey;
|
import org.hibernate.cache.spi.FilterKey;
|
||||||
|
@ -59,6 +61,7 @@ import org.hibernate.dialect.pagination.LimitHelper;
|
||||||
import org.hibernate.dialect.pagination.NoopLimitHandler;
|
import org.hibernate.dialect.pagination.NoopLimitHandler;
|
||||||
import org.hibernate.engine.internal.TwoPhaseLoad;
|
import org.hibernate.engine.internal.TwoPhaseLoad;
|
||||||
import org.hibernate.engine.jdbc.ColumnNameCache;
|
import org.hibernate.engine.jdbc.ColumnNameCache;
|
||||||
|
import org.hibernate.engine.spi.EntityEntry;
|
||||||
import org.hibernate.engine.spi.EntityKey;
|
import org.hibernate.engine.spi.EntityKey;
|
||||||
import org.hibernate.engine.spi.EntityUniqueKey;
|
import org.hibernate.engine.spi.EntityUniqueKey;
|
||||||
import org.hibernate.engine.spi.PersistenceContext;
|
import org.hibernate.engine.spi.PersistenceContext;
|
||||||
|
@ -195,7 +198,11 @@ public abstract class Loader {
|
||||||
* empty superclass implementation merely returns its first
|
* empty superclass implementation merely returns its first
|
||||||
* argument.
|
* argument.
|
||||||
*/
|
*/
|
||||||
protected String applyLocks(String sql, LockOptions lockOptions, Dialect dialect) throws HibernateException {
|
protected String applyLocks(
|
||||||
|
String sql,
|
||||||
|
QueryParameters parameters,
|
||||||
|
Dialect dialect,
|
||||||
|
List<AfterLoadAction> afterLoadActions) throws HibernateException {
|
||||||
return sql;
|
return sql;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -227,13 +234,48 @@ public abstract class Loader {
|
||||||
/**
|
/**
|
||||||
* Modify the SQL, adding lock hints and comments, if necessary
|
* Modify the SQL, adding lock hints and comments, if necessary
|
||||||
*/
|
*/
|
||||||
protected String preprocessSQL(String sql, QueryParameters parameters, Dialect dialect)
|
protected String preprocessSQL(
|
||||||
throws HibernateException {
|
String sql,
|
||||||
|
QueryParameters parameters,
|
||||||
|
Dialect dialect,
|
||||||
|
List<AfterLoadAction> afterLoadActions) throws HibernateException {
|
||||||
|
sql = applyLocks( sql, parameters, dialect, afterLoadActions );
|
||||||
|
return getFactory().getSettings().isCommentsEnabled()
|
||||||
|
? prependComment( sql, parameters )
|
||||||
|
: sql;
|
||||||
|
}
|
||||||
|
|
||||||
sql = applyLocks( sql, parameters.getLockOptions(), dialect );
|
protected static interface AfterLoadAction {
|
||||||
|
public void afterLoad(SessionImplementor session, Object entity, Loadable persister);
|
||||||
|
}
|
||||||
|
|
||||||
return getFactory().getSettings().isCommentsEnabled() ?
|
protected boolean shouldDelayLockingDueToPaging(
|
||||||
prependComment( sql, parameters ) : sql;
|
String sql,
|
||||||
|
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 );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
parameters.setLockOptions( new LockOptions() );
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private String prependComment(String sql, QueryParameters parameters) {
|
private String prependComment(String sql, QueryParameters parameters) {
|
||||||
|
@ -351,7 +393,7 @@ public abstract class Loader {
|
||||||
resultSet,
|
resultSet,
|
||||||
session,
|
session,
|
||||||
queryParameters.isReadOnly( session )
|
queryParameters.isReadOnly( session )
|
||||||
);
|
);
|
||||||
session.getPersistenceContext().initializeNonLazyCollections();
|
session.getPersistenceContext().initializeNonLazyCollections();
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -410,7 +452,7 @@ public abstract class Loader {
|
||||||
resultSet,
|
resultSet,
|
||||||
session,
|
session,
|
||||||
queryParameters.isReadOnly( session )
|
queryParameters.isReadOnly( session )
|
||||||
);
|
);
|
||||||
session.getPersistenceContext().initializeNonLazyCollections();
|
session.getPersistenceContext().initializeNonLazyCollections();
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -843,7 +885,9 @@ public abstract class Loader {
|
||||||
selection.getMaxRows() :
|
selection.getMaxRows() :
|
||||||
Integer.MAX_VALUE;
|
Integer.MAX_VALUE;
|
||||||
|
|
||||||
final ResultSet rs = executeQueryStatement( queryParameters, false, session );
|
final List<AfterLoadAction> afterLoadActions = new ArrayList<AfterLoadAction>();
|
||||||
|
|
||||||
|
final ResultSet rs = executeQueryStatement( queryParameters, false, afterLoadActions, session );
|
||||||
final Statement st = rs.getStatement();
|
final Statement st = rs.getStatement();
|
||||||
|
|
||||||
// would be great to move all this below here into another method that could also be used
|
// would be great to move all this below here into another method that could also be used
|
||||||
|
@ -853,7 +897,7 @@ public abstract class Loader {
|
||||||
// that I could do the control breaking at the means to know when to stop
|
// that I could do the control breaking at the means to know when to stop
|
||||||
|
|
||||||
try {
|
try {
|
||||||
return processResultSet( rs, queryParameters, session, returnProxies, forcedResultTransformer, maxRows );
|
return processResultSet( rs, queryParameters, session, returnProxies, forcedResultTransformer, maxRows, afterLoadActions );
|
||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
st.close();
|
st.close();
|
||||||
|
@ -867,7 +911,8 @@ public abstract class Loader {
|
||||||
SessionImplementor session,
|
SessionImplementor session,
|
||||||
boolean returnProxies,
|
boolean returnProxies,
|
||||||
ResultTransformer forcedResultTransformer,
|
ResultTransformer forcedResultTransformer,
|
||||||
int maxRows) throws SQLException {
|
int maxRows,
|
||||||
|
List<AfterLoadAction> afterLoadActions) throws SQLException {
|
||||||
final int entitySpan = getEntityPersisters().length;
|
final int entitySpan = getEntityPersisters().length;
|
||||||
final EntityKey optionalObjectKey = getOptionalObjectKey( queryParameters, session );
|
final EntityKey optionalObjectKey = getOptionalObjectKey( queryParameters, session );
|
||||||
final LockMode[] lockModesArray = getLockModes( queryParameters.getLockOptions() );
|
final LockMode[] lockModesArray = getLockModes( queryParameters.getLockOptions() );
|
||||||
|
@ -902,8 +947,16 @@ public abstract class Loader {
|
||||||
|
|
||||||
LOG.tracev( "Done processing result set ({0} rows)", count );
|
LOG.tracev( "Done processing result set ({0} rows)", count );
|
||||||
|
|
||||||
initializeEntitiesAndCollections( hydratedObjects, rs, session, queryParameters.isReadOnly( session ) );
|
initializeEntitiesAndCollections(
|
||||||
if ( createSubselects ) createSubselects( subselectResultKeys, queryParameters, session );
|
hydratedObjects,
|
||||||
|
rs,
|
||||||
|
session,
|
||||||
|
queryParameters.isReadOnly( session ),
|
||||||
|
afterLoadActions
|
||||||
|
);
|
||||||
|
if ( createSubselects ) {
|
||||||
|
createSubselects( subselectResultKeys, queryParameters, session );
|
||||||
|
}
|
||||||
return results;
|
return results;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -989,8 +1042,22 @@ public abstract class Loader {
|
||||||
final List hydratedObjects,
|
final List hydratedObjects,
|
||||||
final Object resultSetId,
|
final Object resultSetId,
|
||||||
final SessionImplementor session,
|
final SessionImplementor session,
|
||||||
final boolean readOnly)
|
final boolean readOnly) throws HibernateException {
|
||||||
throws HibernateException {
|
initializeEntitiesAndCollections(
|
||||||
|
hydratedObjects,
|
||||||
|
resultSetId,
|
||||||
|
session,
|
||||||
|
readOnly,
|
||||||
|
Collections.<AfterLoadAction>emptyList()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void initializeEntitiesAndCollections(
|
||||||
|
final List hydratedObjects,
|
||||||
|
final Object resultSetId,
|
||||||
|
final SessionImplementor session,
|
||||||
|
final boolean readOnly,
|
||||||
|
List<AfterLoadAction> afterLoadActions) throws HibernateException {
|
||||||
|
|
||||||
final CollectionPersister[] collectionPersisters = getCollectionPersisters();
|
final CollectionPersister[] collectionPersisters = getCollectionPersisters();
|
||||||
if ( collectionPersisters != null ) {
|
if ( collectionPersisters != null ) {
|
||||||
|
@ -1042,9 +1109,19 @@ public abstract class Loader {
|
||||||
// split off from initializeEntity. It *must* occur after
|
// split off from initializeEntity. It *must* occur after
|
||||||
// endCollectionLoad to ensure the collection is in the
|
// endCollectionLoad to ensure the collection is in the
|
||||||
// persistence context.
|
// persistence context.
|
||||||
if ( hydratedObjects!=null ) {
|
if ( hydratedObjects != null ) {
|
||||||
for ( Object hydratedObject : hydratedObjects ) {
|
for ( Object hydratedObject : hydratedObjects ) {
|
||||||
TwoPhaseLoad.postLoad( hydratedObject, session, post );
|
TwoPhaseLoad.postLoad( hydratedObject, session, post );
|
||||||
|
if ( afterLoadActions != null ) {
|
||||||
|
for ( AfterLoadAction afterLoadAction : afterLoadActions ) {
|
||||||
|
final EntityEntry entityEntry = session.getPersistenceContext().getEntry( hydratedObject );
|
||||||
|
if ( entityEntry == null ) {
|
||||||
|
// big problem
|
||||||
|
throw new HibernateException( "Could not locate EntityEntry immediately after two-phase load" );
|
||||||
|
}
|
||||||
|
afterLoadAction.afterLoad( session, hydratedObject, (Loadable) entityEntry.getPersister() );
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1721,15 +1798,17 @@ public abstract class Loader {
|
||||||
protected ResultSet executeQueryStatement(
|
protected ResultSet executeQueryStatement(
|
||||||
final QueryParameters queryParameters,
|
final QueryParameters queryParameters,
|
||||||
final boolean scroll,
|
final boolean scroll,
|
||||||
|
List<AfterLoadAction> afterLoadActions,
|
||||||
final SessionImplementor session) throws SQLException {
|
final SessionImplementor session) throws SQLException {
|
||||||
return executeQueryStatement( getSQLString(), queryParameters, scroll, session );
|
return executeQueryStatement( getSQLString(), queryParameters, scroll, afterLoadActions, session );
|
||||||
}
|
}
|
||||||
|
|
||||||
protected ResultSet executeQueryStatement(
|
protected ResultSet executeQueryStatement(
|
||||||
final String sqlStatement,
|
String sqlStatement,
|
||||||
final QueryParameters queryParameters,
|
QueryParameters queryParameters,
|
||||||
final boolean scroll,
|
boolean scroll,
|
||||||
final SessionImplementor session) throws SQLException {
|
List<AfterLoadAction> afterLoadActions,
|
||||||
|
SessionImplementor session) throws SQLException {
|
||||||
|
|
||||||
// Processing query filters.
|
// Processing query filters.
|
||||||
queryParameters.processFilters( sqlStatement, session );
|
queryParameters.processFilters( sqlStatement, session );
|
||||||
|
@ -1742,7 +1821,7 @@ public abstract class Loader {
|
||||||
String sql = limitHandler.getProcessedSql();
|
String sql = limitHandler.getProcessedSql();
|
||||||
|
|
||||||
// Adding locks and comments.
|
// Adding locks and comments.
|
||||||
sql = preprocessSQL( sql, queryParameters, getFactory().getDialect() );
|
sql = preprocessSQL( sql, queryParameters, getFactory().getDialect(), afterLoadActions );
|
||||||
|
|
||||||
final PreparedStatement st = prepareQueryStatement( sql, queryParameters, limitHandler, scroll, session );
|
final PreparedStatement st = prepareQueryStatement( sql, queryParameters, limitHandler, scroll, session );
|
||||||
return getResultSet( st, queryParameters.getRowSelection(), limitHandler, queryParameters.hasAutoDiscoverScalarTypes(), session );
|
return getResultSet( st, queryParameters.getRowSelection(), limitHandler, queryParameters.hasAutoDiscoverScalarTypes(), session );
|
||||||
|
@ -2499,7 +2578,7 @@ public abstract class Loader {
|
||||||
if ( stats ) startTime = System.currentTimeMillis();
|
if ( stats ) startTime = System.currentTimeMillis();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
final ResultSet rs = executeQueryStatement( queryParameters, true, session );
|
final ResultSet rs = executeQueryStatement( queryParameters, true, Collections.<AfterLoadAction>emptyList(), session );
|
||||||
final PreparedStatement st = (PreparedStatement) rs.getStatement();
|
final PreparedStatement st = (PreparedStatement) rs.getStatement();
|
||||||
|
|
||||||
if ( stats ) {
|
if ( stats ) {
|
||||||
|
|
|
@ -28,6 +28,8 @@ import java.sql.ResultSet;
|
||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
import java.sql.Statement;
|
import java.sql.Statement;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
import org.hibernate.HibernateException;
|
import org.hibernate.HibernateException;
|
||||||
import org.hibernate.dialect.pagination.LimitHelper;
|
import org.hibernate.dialect.pagination.LimitHelper;
|
||||||
|
@ -250,10 +252,11 @@ public class DynamicBatchingCollectionInitializerBuilder extends BatchingCollect
|
||||||
selection.getMaxRows() :
|
selection.getMaxRows() :
|
||||||
Integer.MAX_VALUE;
|
Integer.MAX_VALUE;
|
||||||
|
|
||||||
final ResultSet rs = executeQueryStatement( sql, queryParameters, false, session );
|
final List<AfterLoadAction> afterLoadActions = Collections.emptyList();
|
||||||
|
final ResultSet rs = executeQueryStatement( sql, queryParameters, false, afterLoadActions, session );
|
||||||
final Statement st = rs.getStatement();
|
final Statement st = rs.getStatement();
|
||||||
try {
|
try {
|
||||||
processResultSet( rs, queryParameters, session, true, null, maxRows );
|
processResultSet( rs, queryParameters, session, true, null, maxRows, afterLoadActions );
|
||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
st.close();
|
st.close();
|
||||||
|
|
|
@ -36,14 +36,19 @@ import org.hibernate.LockOptions;
|
||||||
import org.hibernate.QueryException;
|
import org.hibernate.QueryException;
|
||||||
import org.hibernate.ScrollMode;
|
import org.hibernate.ScrollMode;
|
||||||
import org.hibernate.ScrollableResults;
|
import org.hibernate.ScrollableResults;
|
||||||
|
import org.hibernate.Session;
|
||||||
import org.hibernate.dialect.Dialect;
|
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.LoadQueryInfluencers;
|
||||||
import org.hibernate.engine.spi.QueryParameters;
|
import org.hibernate.engine.spi.QueryParameters;
|
||||||
|
import org.hibernate.engine.spi.RowSelection;
|
||||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||||
import org.hibernate.engine.spi.SessionImplementor;
|
import org.hibernate.engine.spi.SessionImplementor;
|
||||||
import org.hibernate.internal.CriteriaImpl;
|
import org.hibernate.internal.CriteriaImpl;
|
||||||
import org.hibernate.internal.util.collections.ArrayHelper;
|
import org.hibernate.internal.util.collections.ArrayHelper;
|
||||||
import org.hibernate.loader.OuterJoinLoader;
|
import org.hibernate.loader.OuterJoinLoader;
|
||||||
|
import org.hibernate.persister.entity.Loadable;
|
||||||
import org.hibernate.persister.entity.Lockable;
|
import org.hibernate.persister.entity.Lockable;
|
||||||
import org.hibernate.persister.entity.OuterJoinLoadable;
|
import org.hibernate.persister.entity.OuterJoinLoadable;
|
||||||
import org.hibernate.transform.ResultTransformer;
|
import org.hibernate.transform.ResultTransformer;
|
||||||
|
@ -190,12 +195,55 @@ public class CriteriaLoader extends OuterJoinLoader {
|
||||||
return querySpaces;
|
return querySpaces;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected String applyLocks(String sqlSelectString, LockOptions lockOptions, Dialect dialect) throws QueryException {
|
@Override
|
||||||
|
protected String applyLocks(
|
||||||
|
String sql,
|
||||||
|
QueryParameters parameters,
|
||||||
|
Dialect dialect,
|
||||||
|
List<AfterLoadAction> afterLoadActions) throws QueryException {
|
||||||
|
final LockOptions lockOptions = parameters.getLockOptions();
|
||||||
if ( lockOptions == null ||
|
if ( lockOptions == null ||
|
||||||
( lockOptions.getLockMode() == LockMode.NONE && lockOptions.getAliasLockCount() == 0 ) ) {
|
( lockOptions.getLockMode() == LockMode.NONE && lockOptions.getAliasLockCount() == 0 ) ) {
|
||||||
return sqlSelectString;
|
return sql;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// user is request locking, lets see if we can apply locking directly to the SQL...
|
||||||
|
|
||||||
|
// 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 );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
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());
|
final LockOptions locks = new LockOptions(lockOptions.getLockMode());
|
||||||
locks.setScope( lockOptions.getScope());
|
locks.setScope( lockOptions.getScope());
|
||||||
locks.setTimeOut( lockOptions.getTimeOut());
|
locks.setTimeOut( lockOptions.getTimeOut());
|
||||||
|
@ -213,7 +261,7 @@ public class CriteriaLoader extends OuterJoinLoader {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return dialect.applyLocksToSql( sqlSelectString, locks, keyColumnNames );
|
return dialect.applyLocksToSql( sql, locks, keyColumnNames );
|
||||||
}
|
}
|
||||||
|
|
||||||
protected LockMode[] getLockModes(LockOptions lockOptions) {
|
protected LockMode[] getLockModes(LockOptions lockOptions) {
|
||||||
|
|
|
@ -27,6 +27,7 @@ import java.sql.ResultSet;
|
||||||
import java.sql.ResultSetMetaData;
|
import java.sql.ResultSetMetaData;
|
||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
@ -38,7 +39,12 @@ import org.hibernate.LockMode;
|
||||||
import org.hibernate.LockOptions;
|
import org.hibernate.LockOptions;
|
||||||
import org.hibernate.QueryException;
|
import org.hibernate.QueryException;
|
||||||
import org.hibernate.ScrollableResults;
|
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.QueryParameters;
|
||||||
|
import org.hibernate.engine.spi.RowSelection;
|
||||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||||
import org.hibernate.engine.spi.SessionImplementor;
|
import org.hibernate.engine.spi.SessionImplementor;
|
||||||
import org.hibernate.hql.internal.HolderInstantiator;
|
import org.hibernate.hql.internal.HolderInstantiator;
|
||||||
|
@ -50,6 +56,7 @@ import org.hibernate.loader.Loader;
|
||||||
import org.hibernate.persister.collection.CollectionPersister;
|
import org.hibernate.persister.collection.CollectionPersister;
|
||||||
import org.hibernate.persister.collection.QueryableCollection;
|
import org.hibernate.persister.collection.QueryableCollection;
|
||||||
import org.hibernate.persister.entity.Loadable;
|
import org.hibernate.persister.entity.Loadable;
|
||||||
|
import org.hibernate.persister.entity.Lockable;
|
||||||
import org.hibernate.persister.entity.Queryable;
|
import org.hibernate.persister.entity.Queryable;
|
||||||
import org.hibernate.transform.ResultTransformer;
|
import org.hibernate.transform.ResultTransformer;
|
||||||
import org.hibernate.type.CollectionType;
|
import org.hibernate.type.CollectionType;
|
||||||
|
@ -331,6 +338,35 @@ public class CustomLoader extends Loader {
|
||||||
return list( session, queryParameters, querySpaces, resultTypes );
|
return list( session, queryParameters, querySpaces, resultTypes );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String applyLocks(
|
||||||
|
String sql,
|
||||||
|
QueryParameters parameters,
|
||||||
|
Dialect dialect,
|
||||||
|
List<AfterLoadAction> afterLoadActions) throws QueryException {
|
||||||
|
final LockOptions lockOptions = parameters.getLockOptions();
|
||||||
|
if ( lockOptions == null ||
|
||||||
|
( lockOptions.getLockMode() == LockMode.NONE && lockOptions.getAliasLockCount() == 0 ) ) {
|
||||||
|
return sql;
|
||||||
|
}
|
||||||
|
|
||||||
|
// user is request locking, lets see if we can apply locking directly to the SQL...
|
||||||
|
|
||||||
|
// some dialects wont allow locking with paging...
|
||||||
|
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.getLockOptions().setLockMode( LockMode.READ );
|
||||||
|
|
||||||
|
return sql;
|
||||||
|
}
|
||||||
|
|
||||||
public ScrollableResults scroll(
|
public ScrollableResults scroll(
|
||||||
final QueryParameters queryParameters,
|
final QueryParameters queryParameters,
|
||||||
final SessionImplementor session) throws HibernateException {
|
final SessionImplementor session) throws HibernateException {
|
||||||
|
|
|
@ -27,6 +27,7 @@ import java.io.Serializable;
|
||||||
import java.sql.ResultSet;
|
import java.sql.ResultSet;
|
||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
import java.sql.Statement;
|
import java.sql.Statement;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import org.jboss.logging.Logger;
|
import org.jboss.logging.Logger;
|
||||||
|
@ -253,10 +254,11 @@ public class DynamicBatchingEntityLoaderBuilder extends BatchingEntityLoaderBuil
|
||||||
selection.getMaxRows() :
|
selection.getMaxRows() :
|
||||||
Integer.MAX_VALUE;
|
Integer.MAX_VALUE;
|
||||||
|
|
||||||
final ResultSet rs = executeQueryStatement( sql, queryParameters, false, session );
|
final List<AfterLoadAction> afterLoadActions = new ArrayList<AfterLoadAction>();
|
||||||
|
final ResultSet rs = executeQueryStatement( sql, queryParameters, false, afterLoadActions, session );
|
||||||
final Statement st = rs.getStatement();
|
final Statement st = rs.getStatement();
|
||||||
try {
|
try {
|
||||||
return processResultSet( rs, queryParameters, session, false, null, maxRows );
|
return processResultSet( rs, queryParameters, session, false, null, maxRows, afterLoadActions );
|
||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
st.close();
|
st.close();
|
||||||
|
|
|
@ -23,10 +23,12 @@
|
||||||
*/
|
*/
|
||||||
package org.hibernate.loader.hql;
|
package org.hibernate.loader.hql;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
import java.sql.PreparedStatement;
|
import java.sql.PreparedStatement;
|
||||||
import java.sql.ResultSet;
|
import java.sql.ResultSet;
|
||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
@ -37,8 +39,12 @@ import org.hibernate.LockMode;
|
||||||
import org.hibernate.LockOptions;
|
import org.hibernate.LockOptions;
|
||||||
import org.hibernate.QueryException;
|
import org.hibernate.QueryException;
|
||||||
import org.hibernate.ScrollableResults;
|
import org.hibernate.ScrollableResults;
|
||||||
|
import org.hibernate.Session;
|
||||||
import org.hibernate.dialect.Dialect;
|
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.QueryParameters;
|
||||||
|
import org.hibernate.engine.spi.RowSelection;
|
||||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||||
import org.hibernate.engine.spi.SessionImplementor;
|
import org.hibernate.engine.spi.SessionImplementor;
|
||||||
import org.hibernate.event.spi.EventSource;
|
import org.hibernate.event.spi.EventSource;
|
||||||
|
@ -307,16 +313,35 @@ public class QueryLoader extends BasicLoader {
|
||||||
return lockModesArray;
|
return lockModesArray;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected String applyLocks(String sql, LockOptions lockOptions, Dialect dialect) throws QueryException {
|
@Override
|
||||||
|
protected String applyLocks(
|
||||||
|
String sql,
|
||||||
|
QueryParameters parameters,
|
||||||
|
Dialect dialect,
|
||||||
|
List<AfterLoadAction> afterLoadActions) throws QueryException {
|
||||||
// can't cache this stuff either (per-invocation)
|
// can't cache this stuff either (per-invocation)
|
||||||
// we are given a map of user-alias -> lock mode
|
// we are given a map of user-alias -> lock mode
|
||||||
// create a new map of sql-alias -> lock mode
|
// create a new map of sql-alias -> lock mode
|
||||||
|
|
||||||
|
final LockOptions lockOptions = parameters.getLockOptions();
|
||||||
|
|
||||||
if ( lockOptions == null ||
|
if ( lockOptions == null ||
|
||||||
( lockOptions.getLockMode() == LockMode.NONE && lockOptions.getAliasLockCount() == 0 ) ) {
|
( lockOptions.getLockMode() == LockMode.NONE && lockOptions.getAliasLockCount() == 0 ) ) {
|
||||||
return sql;
|
return sql;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// 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 ) ) {
|
||||||
|
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.
|
||||||
|
|
||||||
|
|
||||||
// we need both the set of locks and the columns to reference in locks
|
// we need both the set of locks and the columns to reference in locks
|
||||||
// as the ultimate output of this section...
|
// as the ultimate output of this section...
|
||||||
final LockOptions locks = new LockOptions( lockOptions.getLockMode() );
|
final LockOptions locks = new LockOptions( lockOptions.getLockMode() );
|
||||||
|
@ -490,7 +515,7 @@ public class QueryLoader extends BasicLoader {
|
||||||
if ( queryParameters.isCallable() ) {
|
if ( queryParameters.isCallable() ) {
|
||||||
throw new QueryException("iterate() not supported for callable statements");
|
throw new QueryException("iterate() not supported for callable statements");
|
||||||
}
|
}
|
||||||
final ResultSet rs = executeQueryStatement( queryParameters, false, session );
|
final ResultSet rs = executeQueryStatement( queryParameters, false, Collections.<AfterLoadAction>emptyList(), session );
|
||||||
final PreparedStatement st = (PreparedStatement) rs.getStatement();
|
final PreparedStatement st = (PreparedStatement) rs.getStatement();
|
||||||
final Iterator result = new IteratorImpl(
|
final Iterator result = new IteratorImpl(
|
||||||
rs,
|
rs,
|
||||||
|
|
|
@ -0,0 +1,61 @@
|
||||||
|
/*
|
||||||
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
|
*
|
||||||
|
* Copyright (c) 2012, 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.test.locking.paging;
|
||||||
|
|
||||||
|
import javax.persistence.Entity;
|
||||||
|
import javax.persistence.Id;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Steve Ebersole
|
||||||
|
*/
|
||||||
|
@Entity
|
||||||
|
public class Door {
|
||||||
|
private Integer id;
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
public Door() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public Door(Integer id, String name) {
|
||||||
|
this.id = id;
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Id
|
||||||
|
public Integer getId() {
|
||||||
|
return this.id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setId(Integer id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setName(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,131 @@
|
||||||
|
/*
|
||||||
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
|
*
|
||||||
|
* Copyright (c) 2012, 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.test.locking.paging;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.hibernate.Criteria;
|
||||||
|
import org.hibernate.LockMode;
|
||||||
|
import org.hibernate.LockOptions;
|
||||||
|
import org.hibernate.Query;
|
||||||
|
import org.hibernate.SQLQuery;
|
||||||
|
import org.hibernate.Session;
|
||||||
|
|
||||||
|
import org.junit.After;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Ignore;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import org.hibernate.testing.TestForIssue;
|
||||||
|
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test of paging and locking in combination
|
||||||
|
*
|
||||||
|
* @author Steve Ebersole
|
||||||
|
*/
|
||||||
|
@TestForIssue( jiraKey = "HHH-1168" )
|
||||||
|
public class PagingAndLockingTest extends BaseCoreFunctionalTestCase {
|
||||||
|
@Override
|
||||||
|
protected Class<?>[] getAnnotatedClasses() {
|
||||||
|
return new Class[] { Door.class };
|
||||||
|
}
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void createTestData() {
|
||||||
|
Session session = openSession();
|
||||||
|
session.beginTransaction();
|
||||||
|
session.save( new Door( 1, "Front" ) );
|
||||||
|
session.save( new Door( 2, "Back" ) );
|
||||||
|
session.save( new Door( 3, "Garage" ) );
|
||||||
|
session.save( new Door( 4, "French" ) );
|
||||||
|
session.getTransaction().commit();
|
||||||
|
session.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
@After
|
||||||
|
public void deleteTestData() {
|
||||||
|
Session session = openSession();
|
||||||
|
session.beginTransaction();
|
||||||
|
session.createQuery( "delete Door" ).executeUpdate();
|
||||||
|
session.getTransaction().commit();
|
||||||
|
session.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testHql() {
|
||||||
|
Session session = openSession();
|
||||||
|
session.beginTransaction();
|
||||||
|
Query qry = session.createQuery( "from Door" );
|
||||||
|
qry.getLockOptions().setLockMode( LockMode.PESSIMISTIC_WRITE );
|
||||||
|
qry.setFirstResult( 2 );
|
||||||
|
qry.setMaxResults( 2 );
|
||||||
|
@SuppressWarnings("unchecked") List<Door> results = qry.list();
|
||||||
|
assertEquals( 2, results.size() );
|
||||||
|
for ( Door door : results ) {
|
||||||
|
assertEquals( LockMode.PESSIMISTIC_WRITE, session.getCurrentLockMode( door ) );
|
||||||
|
}
|
||||||
|
session.getTransaction().commit();
|
||||||
|
session.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCriteria() {
|
||||||
|
Session session = openSession();
|
||||||
|
session.beginTransaction();
|
||||||
|
Criteria criteria = session.createCriteria( Door.class );
|
||||||
|
criteria.setLockMode( LockMode.PESSIMISTIC_WRITE );
|
||||||
|
criteria.setFirstResult( 2 );
|
||||||
|
criteria.setMaxResults( 2 );
|
||||||
|
@SuppressWarnings("unchecked") List<Door> results = criteria.list();
|
||||||
|
assertEquals( 2, results.size() );
|
||||||
|
for ( Door door : results ) {
|
||||||
|
assertEquals( LockMode.PESSIMISTIC_WRITE, session.getCurrentLockMode( door ) );
|
||||||
|
}
|
||||||
|
session.getTransaction().commit();
|
||||||
|
session.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
// @Ignore( "Support for locking on native-sql queries not yet implemented" )
|
||||||
|
public void testNativeSql() {
|
||||||
|
Session session = openSession();
|
||||||
|
session.beginTransaction();
|
||||||
|
SQLQuery qry = session.createSQLQuery( "select * from door" );
|
||||||
|
qry.addRoot( "door", Door.class );
|
||||||
|
qry.getLockOptions().setLockMode( LockMode.PESSIMISTIC_WRITE );
|
||||||
|
qry.setFirstResult( 2 );
|
||||||
|
qry.setMaxResults( 2 );
|
||||||
|
@SuppressWarnings("unchecked") List<Door> results = qry.list();
|
||||||
|
assertEquals( 2, results.size() );
|
||||||
|
for ( Door door : results ) {
|
||||||
|
assertEquals( LockMode.PESSIMISTIC_WRITE, session.getCurrentLockMode( door ) );
|
||||||
|
}
|
||||||
|
session.getTransaction().commit();
|
||||||
|
session.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -20,7 +20,7 @@
|
||||||
# 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
|
||||||
#
|
|
||||||
hibernate.dialect org.hibernate.dialect.H2Dialect
|
hibernate.dialect org.hibernate.dialect.H2Dialect
|
||||||
hibernate.connection.driver_class org.h2.Driver
|
hibernate.connection.driver_class org.h2.Driver
|
||||||
hibernate.connection.url jdbc:h2:mem:db1;DB_CLOSE_DELAY=-1;MVCC=TRUE
|
hibernate.connection.url jdbc:h2:mem:db1;DB_CLOSE_DELAY=-1;MVCC=TRUE
|
||||||
|
|
|
@ -53,6 +53,7 @@ import org.hibernate.engine.query.spi.NamedParameterDescriptor;
|
||||||
import org.hibernate.engine.query.spi.OrdinalParameterDescriptor;
|
import org.hibernate.engine.query.spi.OrdinalParameterDescriptor;
|
||||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||||
import org.hibernate.hql.internal.QueryExecutionRequestException;
|
import org.hibernate.hql.internal.QueryExecutionRequestException;
|
||||||
|
import org.hibernate.internal.SQLQueryImpl;
|
||||||
import org.hibernate.jpa.AvailableSettings;
|
import org.hibernate.jpa.AvailableSettings;
|
||||||
import org.hibernate.jpa.HibernateQuery;
|
import org.hibernate.jpa.HibernateQuery;
|
||||||
import org.hibernate.jpa.internal.util.ConfigurationHelper;
|
import org.hibernate.jpa.internal.util.ConfigurationHelper;
|
||||||
|
@ -242,12 +243,13 @@ public class QueryImpl<X> extends AbstractQueryImpl<X> implements TypedQuery<X>,
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected boolean canApplyLockModes() {
|
protected boolean canApplyLockModes() {
|
||||||
return org.hibernate.internal.QueryImpl.class.isInstance( query );
|
return org.hibernate.internal.QueryImpl.class.isInstance( query )
|
||||||
|
|| SQLQueryImpl.class.isInstance( query );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void applyAliasSpecificLockMode(String alias, LockMode lockMode) {
|
protected void applyAliasSpecificLockMode(String alias, LockMode lockMode) {
|
||||||
( (org.hibernate.internal.QueryImpl) query ).getLockOptions().setAliasSpecificLockMode( alias, lockMode );
|
query.getLockOptions().setAliasSpecificLockMode( alias, lockMode );
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -631,18 +633,16 @@ public class QueryImpl<X> extends AbstractQueryImpl<X> implements TypedQuery<X>,
|
||||||
throw new IllegalStateException( "Not a JPAQL/Criteria query" );
|
throw new IllegalStateException( "Not a JPAQL/Criteria query" );
|
||||||
}
|
}
|
||||||
this.jpaLockMode = lockModeType;
|
this.jpaLockMode = lockModeType;
|
||||||
( (org.hibernate.internal.QueryImpl) query ).getLockOptions().setLockMode(
|
query.getLockOptions().setLockMode( LockModeTypeHelper.getLockMode( lockModeType ) );
|
||||||
LockModeTypeHelper.getLockMode( lockModeType )
|
if ( getHints() != null && getHints().containsKey( AvailableSettings.LOCK_TIMEOUT ) ) {
|
||||||
);
|
applyLockTimeout( ConfigurationHelper.getInteger( getHints().get( AvailableSettings.LOCK_TIMEOUT ) ) );
|
||||||
if ( getHints()!=null && getHints().containsKey( AvailableSettings.LOCK_TIMEOUT ) ) {
|
|
||||||
applyLockTimeout( ConfigurationHelper.getInteger( getHints().get( AvailableSettings.LOCK_TIMEOUT )) );
|
|
||||||
}
|
}
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void applyLockTimeout(int timeout) {
|
protected void applyLockTimeout(int timeout) {
|
||||||
( (org.hibernate.internal.QueryImpl) query ).getLockOptions().setTimeOut( timeout );
|
query.getLockOptions().setTimeOut( timeout );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -82,6 +82,32 @@ public class QueryLockingTest extends BaseEntityManagerFunctionalTestCase {
|
||||||
em.close();
|
em.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testNativeSql() {
|
||||||
|
EntityManager em = getOrCreateEntityManager();
|
||||||
|
em.getTransaction().begin();
|
||||||
|
QueryImpl query = em.createNativeQuery( "select * from lockable l" ).unwrap( QueryImpl.class );
|
||||||
|
|
||||||
|
org.hibernate.internal.SQLQueryImpl hibernateQuery = (org.hibernate.internal.SQLQueryImpl) query.getHibernateQuery();
|
||||||
|
// assertEquals( LockMode.NONE, hibernateQuery.getLockOptions().getLockMode() );
|
||||||
|
// assertNull( hibernateQuery.getLockOptions().getAliasSpecificLockMode( "l" ) );
|
||||||
|
// assertEquals( LockMode.NONE, hibernateQuery.getLockOptions().getEffectiveLockMode( "l" ) );
|
||||||
|
|
||||||
|
// NOTE : LockModeType.READ should map to LockMode.OPTIMISTIC
|
||||||
|
query.setLockMode( LockModeType.READ );
|
||||||
|
assertEquals( LockMode.OPTIMISTIC, hibernateQuery.getLockOptions().getLockMode() );
|
||||||
|
assertNull( hibernateQuery.getLockOptions().getAliasSpecificLockMode( "l" ) );
|
||||||
|
assertEquals( LockMode.OPTIMISTIC, hibernateQuery.getLockOptions().getEffectiveLockMode( "l" ) );
|
||||||
|
|
||||||
|
query.setHint( AvailableSettings.ALIAS_SPECIFIC_LOCK_MODE+".l", LockModeType.PESSIMISTIC_WRITE );
|
||||||
|
assertEquals( LockMode.OPTIMISTIC, hibernateQuery.getLockOptions().getLockMode() );
|
||||||
|
assertEquals( LockMode.PESSIMISTIC_WRITE, hibernateQuery.getLockOptions().getAliasSpecificLockMode( "l" ) );
|
||||||
|
assertEquals( LockMode.PESSIMISTIC_WRITE, hibernateQuery.getLockOptions().getEffectiveLockMode( "l" ) );
|
||||||
|
|
||||||
|
em.getTransaction().commit();
|
||||||
|
em.close();
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testPessimisticForcedIncrementOverall() {
|
public void testPessimisticForcedIncrementOverall() {
|
||||||
EntityManager em = getOrCreateEntityManager();
|
EntityManager em = getOrCreateEntityManager();
|
||||||
|
|
Loading…
Reference in New Issue