HHH-6736 Added support for SELECT ... FOR UPDATE SKIP LOCKED
This commit is contained in:
parent
59bb86978e
commit
e0cfc6bf2e
|
@ -263,6 +263,11 @@
|
|||
<entry><para>acquired upon explicit user request using a <code>SELECT ... FOR UPDATE NOWAIT</code> in
|
||||
Oracle.</para></entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>LockMode.UPGRADE_SKIPLOCKED</entry>
|
||||
<entry><para>acquired upon explicit user request using a <code>SELECT ... FOR UPDATE SKIP LOCKED</code> in
|
||||
Oracle, or <code>SELECT ... with (rowlock,updlock,readpast) in SQL Server</code>.</para></entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>LockMode.READ</entry>
|
||||
<entry><para>acquired automatically when Hibernate reads data under <phrase>Repeatable Read</phrase> or
|
||||
|
@ -299,17 +304,18 @@
|
|||
</listitem>
|
||||
</itemizedlist>
|
||||
<para>
|
||||
If you call <methodname>Session.load()</methodname> with option <option>UPGRADE</option> or
|
||||
<option>UPGRADE_NOWAIT</option>, and the requested object is not already loaded by the session, the object is
|
||||
loaded using <code>SELECT ... FOR UPDATE</code>. If you call <methodname>load()</methodname> for an object that
|
||||
is already loaded with a less restrictive lock than the one you request, Hibernate calls
|
||||
<methodname>lock()</methodname> for that object.
|
||||
If you call <methodname>Session.load()</methodname> with option <option>UPGRADE</option>,
|
||||
<option>UPGRADE_NOWAIT</option> or <option>UPGRADE_SKIPLOCKED</option>, and the requested object is not already
|
||||
loaded by the session, the object is loaded using <code>SELECT ... FOR UPDATE</code>. If you call
|
||||
<methodname>load()</methodname> for an object that is already loaded with a less restrictive lock than the one
|
||||
you request, Hibernate calls <methodname>lock()</methodname> for that object.
|
||||
</para>
|
||||
<para>
|
||||
<methodname>Session.lock()</methodname> performs a version number check if the specified lock mode is
|
||||
<literal>READ</literal>, <literal>UPGRADE</literal>, or <literal>UPGRADE_NOWAIT</literal>. In the case of
|
||||
<literal>UPGRADE</literal> or <literal>UPGRADE_NOWAIT</literal>, <code>SELECT ... FOR UPDATE</code> syntax is
|
||||
used.
|
||||
<literal>READ</literal>, <literal>UPGRADE</literal>, <literal>UPGRADE_NOWAIT</literal> or
|
||||
<literal>UPGRADE_SKIPLOCKED</literal>. In the case of <literal>UPGRADE</literal>,
|
||||
<literal>UPGRADE_NOWAIT</literal> or <literal>UPGRADE_SKIPLOCKED</literal>, <code>SELECT ... FOR UPDATE</code>
|
||||
syntax is used.
|
||||
</para>
|
||||
<para>
|
||||
If the requested lock mode is not supported by the database, Hibernate uses an appropriate alternate mode
|
||||
|
|
|
@ -66,6 +66,15 @@ public enum LockMode {
|
|||
* <tt>UPGRADE</tt>.
|
||||
*/
|
||||
UPGRADE_NOWAIT( 10 ),
|
||||
|
||||
/**
|
||||
* Attempt to obtain an upgrade lock, using an Oracle-style
|
||||
* <tt>select for update skip locked</tt>. The semantics of
|
||||
* this lock mode, once obtained, are the same as
|
||||
* <tt>UPGRADE</tt>.
|
||||
*/
|
||||
UPGRADE_SKIPLOCKED( 10 ),
|
||||
|
||||
/**
|
||||
* A <tt>WRITE</tt> lock is obtained when an object is updated
|
||||
* or inserted. This lock mode is for internal use only and is
|
||||
|
|
|
@ -64,6 +64,12 @@ public class LockOptions implements Serializable {
|
|||
*/
|
||||
public static final int WAIT_FOREVER = -1;
|
||||
|
||||
/**
|
||||
* Indicates that rows that are already locked should be skipped.
|
||||
* @see #getTimeOut()
|
||||
*/
|
||||
public static final int SKIP_LOCKED = -2;
|
||||
|
||||
private LockMode lockMode = LockMode.NONE;
|
||||
private int timeout = WAIT_FOREVER;
|
||||
|
||||
|
@ -221,9 +227,9 @@ public class LockOptions implements Serializable {
|
|||
* The timeout is the amount of time, in milliseconds, we should instruct the database
|
||||
* to wait for any requested pessimistic lock acquisition.
|
||||
* <p/>
|
||||
* {@link #NO_WAIT} and {@link #WAIT_FOREVER} represent 2 "magic" values.
|
||||
* {@link #NO_WAIT}, {@link #WAIT_FOREVER} or {@link #SKIP_LOCKED} represent 3 "magic" values.
|
||||
*
|
||||
* @return timeout in milliseconds, or {@link #NO_WAIT} or {@link #WAIT_FOREVER}
|
||||
* @return timeout in milliseconds, {@link #NO_WAIT}, {@link #WAIT_FOREVER} or {@link #SKIP_LOCKED}
|
||||
*/
|
||||
public int getTimeOut() {
|
||||
return timeout;
|
||||
|
|
|
@ -375,6 +375,9 @@ public abstract class ResultSetMappingBinder {
|
|||
else if ( "upgrade-nowait".equals( lockMode ) ) {
|
||||
return LockMode.UPGRADE_NOWAIT;
|
||||
}
|
||||
else if ( "upgrade-skiplocked".equals( lockMode )) {
|
||||
return LockMode.UPGRADE_SKIPLOCKED;
|
||||
}
|
||||
else if ( "write".equals( lockMode ) ) {
|
||||
return LockMode.WRITE;
|
||||
}
|
||||
|
|
|
@ -23,40 +23,14 @@
|
|||
*/
|
||||
package org.hibernate.dialect;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.sql.Blob;
|
||||
import java.sql.CallableStatement;
|
||||
import java.sql.Clob;
|
||||
import java.sql.NClob;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Types;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
import java.util.Set;
|
||||
|
||||
import org.hibernate.HibernateException;
|
||||
import org.hibernate.LockMode;
|
||||
import org.hibernate.LockOptions;
|
||||
import org.hibernate.MappingException;
|
||||
import org.hibernate.NullPrecedence;
|
||||
import org.hibernate.cfg.Environment;
|
||||
import org.hibernate.dialect.function.CastFunction;
|
||||
import org.hibernate.dialect.function.SQLFunction;
|
||||
import org.hibernate.dialect.function.SQLFunctionTemplate;
|
||||
import org.hibernate.dialect.function.StandardAnsiSqlAggregationFunctions;
|
||||
import org.hibernate.dialect.function.StandardSQLFunction;
|
||||
import org.hibernate.dialect.lock.LockingStrategy;
|
||||
import org.hibernate.dialect.lock.OptimisticForceIncrementLockingStrategy;
|
||||
import org.hibernate.dialect.lock.OptimisticLockingStrategy;
|
||||
import org.hibernate.dialect.lock.PessimisticForceIncrementLockingStrategy;
|
||||
import org.hibernate.dialect.lock.PessimisticReadSelectLockingStrategy;
|
||||
import org.hibernate.dialect.lock.PessimisticWriteSelectLockingStrategy;
|
||||
import org.hibernate.dialect.lock.SelectLockingStrategy;
|
||||
import org.hibernate.dialect.function.*;
|
||||
import org.hibernate.dialect.lock.*;
|
||||
import org.hibernate.dialect.pagination.LegacyLimitHandler;
|
||||
import org.hibernate.dialect.pagination.LimitHandler;
|
||||
import org.hibernate.dialect.unique.DefaultUniqueDelegate;
|
||||
|
@ -78,16 +52,17 @@ import org.hibernate.internal.util.collections.ArrayHelper;
|
|||
import org.hibernate.internal.util.io.StreamCopier;
|
||||
import org.hibernate.mapping.Column;
|
||||
import org.hibernate.persister.entity.Lockable;
|
||||
import org.hibernate.sql.ANSICaseFragment;
|
||||
import org.hibernate.sql.ANSIJoinFragment;
|
||||
import org.hibernate.sql.CaseFragment;
|
||||
import org.hibernate.sql.ForUpdateFragment;
|
||||
import org.hibernate.sql.JoinFragment;
|
||||
import org.hibernate.sql.*;
|
||||
import org.hibernate.type.StandardBasicTypes;
|
||||
import org.hibernate.type.descriptor.sql.ClobTypeDescriptor;
|
||||
import org.hibernate.type.descriptor.sql.SqlTypeDescriptor;
|
||||
import org.jboss.logging.Logger;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.sql.*;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* Represents a dialect of SQL implemented by a particular RDBMS.
|
||||
* Subclasses implement Hibernate compatibility with different systems.<br>
|
||||
|
@ -1195,6 +1170,8 @@ public abstract class Dialect implements ConversionContext {
|
|||
case FORCE:
|
||||
case PESSIMISTIC_FORCE_INCREMENT:
|
||||
return getForUpdateNowaitString();
|
||||
case UPGRADE_SKIPLOCKED:
|
||||
return getForUpdateSkipLockedString();
|
||||
default:
|
||||
return "";
|
||||
}
|
||||
|
@ -1313,6 +1290,16 @@ public abstract class Dialect implements ConversionContext {
|
|||
return getForUpdateString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the <tt>FOR UPDATE SKIP LOCKED</tt> syntax specific to this dialect.
|
||||
*
|
||||
* @return The appropriate <tt>FOR UPDATE SKIP LOCKED</tt> clause string.
|
||||
*/
|
||||
public String getForUpdateSkipLockedString() {
|
||||
// by default we report no support for SKIP_LOCKED lock semantics
|
||||
return getForUpdateString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the <tt>FOR UPDATE OF column_list NOWAIT</tt> fragment appropriate
|
||||
* for this dialect given the aliases of the columns to be write locked.
|
||||
|
@ -1324,6 +1311,17 @@ public abstract class Dialect implements ConversionContext {
|
|||
return getForUpdateString( aliases );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the <tt>FOR UPDATE OF column_list SKIP LOCKED</tt> fragment appropriate
|
||||
* for this dialect given the aliases of the columns to be write locked.
|
||||
*
|
||||
* @param aliases The columns to be write locked.
|
||||
* @return The appropriate <tt>FOR UPDATE colunm_list SKIP LOCKED</tt> clause string.
|
||||
*/
|
||||
public String getForUpdateSkipLockedString(String aliases) {
|
||||
return getForUpdateString( aliases );
|
||||
}
|
||||
|
||||
/**
|
||||
* Some dialects support an alternative means to <tt>SELECT FOR UPDATE</tt>,
|
||||
* whereby a "lock hint" is appends to the table name in the from clause.
|
||||
|
@ -2427,7 +2425,7 @@ public abstract class Dialect implements ConversionContext {
|
|||
public UniqueDelegate getUniqueDelegate() {
|
||||
return uniqueDelegate;
|
||||
}
|
||||
|
||||
|
||||
public String getNotExpression( String expression ) {
|
||||
return "not " + expression;
|
||||
}
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package org.hibernate.dialect;
|
||||
import org.hibernate.LockOptions;
|
||||
import org.hibernate.sql.ANSIJoinFragment;
|
||||
import org.hibernate.sql.JoinFragment;
|
||||
|
||||
|
@ -45,4 +46,21 @@ public class Oracle10gDialect extends Oracle9iDialect {
|
|||
public JoinFragment createOuterJoinFragment() {
|
||||
return new ANSIJoinFragment();
|
||||
}
|
||||
|
||||
public String getWriteLockString(int timeout) {
|
||||
if ( timeout == LockOptions.SKIP_LOCKED ) {
|
||||
return getForUpdateSkipLockedString();
|
||||
}
|
||||
else {
|
||||
return super.getWriteLockString(timeout);
|
||||
}
|
||||
}
|
||||
|
||||
public String getForUpdateSkipLockedString() {
|
||||
return " for update skip locked";
|
||||
}
|
||||
|
||||
public String getForUpdateSkipLockedString(String aliases) {
|
||||
return getForUpdateString() + " of " + aliases + " skip locked";
|
||||
}
|
||||
}
|
||||
|
|
|
@ -134,6 +134,8 @@ public class SQLServerDialect extends AbstractTransactSQLDialect {
|
|||
return tableName + " with (updlock, rowlock)";
|
||||
case PESSIMISTIC_READ:
|
||||
return tableName + " with (holdlock, rowlock)";
|
||||
case UPGRADE_SKIPLOCKED:
|
||||
return tableName + " with (updlock, rowlock, readpast)";
|
||||
default:
|
||||
return tableName;
|
||||
}
|
||||
|
|
|
@ -54,11 +54,18 @@ public abstract class AbstractSelectLockingStrategy implements LockingStrategy {
|
|||
protected abstract String generateLockString(int lockTimeout);
|
||||
|
||||
protected String determineSql(int timeout) {
|
||||
return timeout == LockOptions.WAIT_FOREVER
|
||||
? waitForeverSql
|
||||
: timeout == LockOptions.NO_WAIT
|
||||
? getNoWaitSql()
|
||||
: generateLockString( timeout );
|
||||
if ( timeout == LockOptions.WAIT_FOREVER) {
|
||||
return waitForeverSql;
|
||||
}
|
||||
else if ( timeout == LockOptions.NO_WAIT) {
|
||||
return getNoWaitSql();
|
||||
}
|
||||
else if ( timeout == LockOptions.SKIP_LOCKED) {
|
||||
return getSkipLockedSql();
|
||||
}
|
||||
else {
|
||||
return generateLockString( timeout );
|
||||
}
|
||||
}
|
||||
|
||||
private String noWaitSql;
|
||||
|
@ -69,4 +76,13 @@ public abstract class AbstractSelectLockingStrategy implements LockingStrategy {
|
|||
}
|
||||
return noWaitSql;
|
||||
}
|
||||
|
||||
private String skipLockedSql;
|
||||
|
||||
public String getSkipLockedSql() {
|
||||
if ( skipLockedSql == null ) {
|
||||
skipLockedSql = generateLockString( LockOptions.SKIP_LOCKED );
|
||||
}
|
||||
return skipLockedSql;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -57,7 +57,8 @@ public class LockModeConverter {
|
|||
}
|
||||
else if ( lockMode == LockMode.PESSIMISTIC_WRITE
|
||||
|| lockMode == LockMode.UPGRADE
|
||||
|| lockMode == LockMode.UPGRADE_NOWAIT ) {
|
||||
|| lockMode == LockMode.UPGRADE_NOWAIT
|
||||
|| lockMode == LockMode.UPGRADE_SKIPLOCKED) {
|
||||
return LockModeType.PESSIMISTIC_WRITE;
|
||||
}
|
||||
else if ( lockMode == LockMode.PESSIMISTIC_FORCE_INCREMENT
|
||||
|
|
|
@ -254,22 +254,24 @@ public abstract class Loader {
|
|||
Dialect dialect,
|
||||
List<AfterLoadAction> afterLoadActions) {
|
||||
if ( dialect.useFollowOnLocking() ) {
|
||||
LOG.usingFollowOnLocking();
|
||||
// currently only one lock mode is allowed in follow-on locking
|
||||
final LockMode lockMode = determineFollowOnLockMode( parameters.getLockOptions() );
|
||||
final LockOptions lockOptions = new LockOptions( lockMode );
|
||||
lockOptions.setTimeOut( parameters.getLockOptions().getTimeOut() );
|
||||
lockOptions.setScope( parameters.getLockOptions().getScope() );
|
||||
afterLoadActions.add(
|
||||
new AfterLoadAction() {
|
||||
@Override
|
||||
public void afterLoad(SessionImplementor session, Object entity, Loadable persister) {
|
||||
( (Session) session ).buildLockRequest( lockOptions ).lock( persister.getEntityName(), entity );
|
||||
if ( lockOptions.getLockMode() != LockMode.UPGRADE_SKIPLOCKED ) {
|
||||
LOG.usingFollowOnLocking();
|
||||
lockOptions.setTimeOut( parameters.getLockOptions().getTimeOut() );
|
||||
lockOptions.setScope( parameters.getLockOptions().getScope() );
|
||||
afterLoadActions.add(
|
||||
new AfterLoadAction() {
|
||||
@Override
|
||||
public void afterLoad(SessionImplementor session, Object entity, Loadable persister) {
|
||||
( (Session) session ).buildLockRequest( lockOptions ).lock( persister.getEntityName(), entity );
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
parameters.setLockOptions( new LockOptions() );
|
||||
return true;
|
||||
);
|
||||
parameters.setLockOptions( new LockOptions() );
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -205,27 +205,28 @@ public class CriteriaLoader extends OuterJoinLoader {
|
|||
}
|
||||
|
||||
if ( dialect.useFollowOnLocking() ) {
|
||||
// Dialect prefers to perform locking in a separate step
|
||||
LOG.usingFollowOnLocking();
|
||||
final LockMode lockMode = determineFollowOnLockMode( lockOptions );
|
||||
if( lockMode != LockMode.UPGRADE_SKIPLOCKED ) {
|
||||
// Dialect prefers to perform locking in a separate step
|
||||
LOG.usingFollowOnLocking();
|
||||
|
||||
final LockMode lockMode = determineFollowOnLockMode( lockOptions );
|
||||
final LockOptions lockOptionsToUse = new LockOptions( lockMode );
|
||||
lockOptionsToUse.setTimeOut( lockOptions.getTimeOut() );
|
||||
lockOptionsToUse.setScope( lockOptions.getScope() );
|
||||
final LockOptions lockOptionsToUse = new LockOptions( lockMode );
|
||||
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;
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
final LockOptions locks = new LockOptions(lockOptions.getLockMode());
|
||||
locks.setScope( lockOptions.getScope());
|
||||
locks.setTimeOut( lockOptions.getTimeOut());
|
||||
|
|
|
@ -1910,6 +1910,7 @@ public abstract class AbstractEntityPersister
|
|||
lockers.put( LockMode.READ, generateLocker( LockMode.READ ) );
|
||||
lockers.put( LockMode.UPGRADE, generateLocker( LockMode.UPGRADE ) );
|
||||
lockers.put( LockMode.UPGRADE_NOWAIT, generateLocker( LockMode.UPGRADE_NOWAIT ) );
|
||||
lockers.put( LockMode.UPGRADE_SKIPLOCKED, generateLocker( LockMode.UPGRADE_SKIPLOCKED ) );
|
||||
lockers.put( LockMode.FORCE, generateLocker( LockMode.FORCE ) );
|
||||
lockers.put( LockMode.PESSIMISTIC_READ, generateLocker( LockMode.PESSIMISTIC_READ ) );
|
||||
lockers.put( LockMode.PESSIMISTIC_WRITE, generateLocker( LockMode.PESSIMISTIC_WRITE ) );
|
||||
|
@ -3851,6 +3852,12 @@ public abstract class AbstractEntityPersister
|
|||
readLoader :
|
||||
createEntityLoader( LockMode.UPGRADE_NOWAIT )
|
||||
);
|
||||
loaders.put(
|
||||
LockMode.UPGRADE_SKIPLOCKED,
|
||||
disableForUpdate ?
|
||||
readLoader :
|
||||
createEntityLoader( LockMode.UPGRADE_SKIPLOCKED )
|
||||
);
|
||||
loaders.put(
|
||||
LockMode.FORCE,
|
||||
disableForUpdate ?
|
||||
|
|
|
@ -39,6 +39,7 @@ import org.hibernate.internal.util.StringHelper;
|
|||
public class ForUpdateFragment {
|
||||
private final StringBuilder aliases = new StringBuilder();
|
||||
private boolean isNowaitEnabled;
|
||||
private boolean isSkipLockedEnabled;
|
||||
private final Dialect dialect;
|
||||
private LockMode lockMode;
|
||||
private LockOptions lockOptions;
|
||||
|
@ -89,6 +90,10 @@ public class ForUpdateFragment {
|
|||
if ( upgradeType == LockMode.UPGRADE_NOWAIT ) {
|
||||
setNowaitEnabled( true );
|
||||
}
|
||||
|
||||
if ( upgradeType == LockMode.UPGRADE_SKIPLOCKED ) {
|
||||
setSkipLockedEnabled( true );
|
||||
}
|
||||
}
|
||||
|
||||
public ForUpdateFragment addTableAlias(String alias) {
|
||||
|
@ -110,13 +115,25 @@ public class ForUpdateFragment {
|
|||
return "";
|
||||
}
|
||||
// TODO: pass lockmode
|
||||
return isNowaitEnabled ?
|
||||
dialect.getForUpdateNowaitString( aliases.toString() ) :
|
||||
dialect.getForUpdateString( aliases.toString() );
|
||||
if(isNowaitEnabled) {
|
||||
return dialect.getForUpdateNowaitString( aliases.toString() );
|
||||
}
|
||||
else if (isSkipLockedEnabled) {
|
||||
return dialect.getForUpdateSkipLockedString( aliases.toString() );
|
||||
}
|
||||
else {
|
||||
return dialect.getForUpdateString( aliases.toString() );
|
||||
}
|
||||
}
|
||||
|
||||
public ForUpdateFragment setNowaitEnabled(boolean nowait) {
|
||||
isNowaitEnabled = nowait;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ForUpdateFragment setSkipLockedEnabled(boolean skipLocked) {
|
||||
isSkipLockedEnabled = skipLocked;
|
||||
return this;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -993,7 +993,7 @@ finder methods for named queries -->
|
|||
<!ATTLIST return alias CDATA #IMPLIED>
|
||||
<!ATTLIST return entity-name CDATA #IMPLIED>
|
||||
<!ATTLIST return class CDATA #IMPLIED>
|
||||
<!ATTLIST return lock-mode (none|read|upgrade|upgrade-nowait|write) "read">
|
||||
<!ATTLIST return lock-mode (none|read|upgrade|upgrade-nowait|upgrade-skiplocked|write) "read">
|
||||
|
||||
<!ELEMENT return-property (return-column*)>
|
||||
<!ATTLIST return-property name CDATA #REQUIRED>
|
||||
|
@ -1008,12 +1008,12 @@ finder methods for named queries -->
|
|||
<!ELEMENT return-join (return-property)*>
|
||||
<!ATTLIST return-join alias CDATA #REQUIRED>
|
||||
<!ATTLIST return-join property CDATA #REQUIRED>
|
||||
<!ATTLIST return-join lock-mode (none|read|upgrade|upgrade-nowait|write) "read">
|
||||
<!ATTLIST return-join lock-mode (none|read|upgrade|upgrade-nowait|upgrade-skiplocked|write) "read">
|
||||
|
||||
<!ELEMENT load-collection (return-property)*>
|
||||
<!ATTLIST load-collection alias CDATA #REQUIRED>
|
||||
<!ATTLIST load-collection role CDATA #REQUIRED>
|
||||
<!ATTLIST load-collection lock-mode (none|read|upgrade|upgrade-nowait|write) "read">
|
||||
<!ATTLIST load-collection lock-mode (none|read|upgrade|upgrade-nowait|upgrade-skiplocked|write) "read">
|
||||
|
||||
<!ELEMENT return-scalar EMPTY>
|
||||
<!ATTLIST return-scalar column CDATA #REQUIRED>
|
||||
|
|
|
@ -1785,6 +1785,7 @@ arbitrary number of queries, and import declarations of arbitrary classes.
|
|||
<xs:enumeration value="read"/>
|
||||
<xs:enumeration value="upgrade"/>
|
||||
<xs:enumeration value="upgrade-nowait"/>
|
||||
<xs:enumeration value="upgrade-skiplocked"/>
|
||||
<xs:enumeration value="write"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
|
|
|
@ -1098,10 +1098,13 @@ public class ParentChildTest extends LegacyTestCase {
|
|||
s3.setCount(3);
|
||||
Simple s4 = new Simple( Long.valueOf(4) );
|
||||
s4.setCount(4);
|
||||
Simple s5 = new Simple( Long.valueOf(5) );
|
||||
s5.setCount(5);
|
||||
s.save( s1 );
|
||||
s.save( s2 );
|
||||
s.save( s3 );
|
||||
s.save( s4 );
|
||||
s.save( s5 );
|
||||
assertTrue( s.getCurrentLockMode(s1)==LockMode.WRITE );
|
||||
tx.commit();
|
||||
s.close();
|
||||
|
@ -1116,6 +1119,8 @@ public class ParentChildTest extends LegacyTestCase {
|
|||
assertTrue( s.getCurrentLockMode(s3)==LockMode.UPGRADE );
|
||||
s4 = (Simple) s.get(Simple.class, new Long(4), LockMode.UPGRADE_NOWAIT);
|
||||
assertTrue( s.getCurrentLockMode(s4)==LockMode.UPGRADE_NOWAIT );
|
||||
s5 = (Simple) s.get(Simple.class, new Long(5), LockMode.UPGRADE_SKIPLOCKED);
|
||||
assertTrue( s.getCurrentLockMode(s5)==LockMode.UPGRADE_SKIPLOCKED );
|
||||
|
||||
s1 = (Simple) s.load(Simple.class, new Long(1), LockMode.UPGRADE); //upgrade
|
||||
assertTrue( s.getCurrentLockMode(s1)==LockMode.UPGRADE );
|
||||
|
@ -1125,6 +1130,8 @@ public class ParentChildTest extends LegacyTestCase {
|
|||
assertTrue( s.getCurrentLockMode(s3)==LockMode.UPGRADE );
|
||||
s4 = (Simple) s.load(Simple.class, new Long(4), LockMode.UPGRADE);
|
||||
assertTrue( s.getCurrentLockMode(s4)==LockMode.UPGRADE_NOWAIT );
|
||||
s5 = (Simple) s.load(Simple.class, new Long(5), LockMode.UPGRADE);
|
||||
assertTrue( s.getCurrentLockMode(s5)==LockMode.UPGRADE_SKIPLOCKED );
|
||||
|
||||
s.lock(s2, LockMode.UPGRADE); //upgrade
|
||||
assertTrue( s.getCurrentLockMode(s2)==LockMode.UPGRADE );
|
||||
|
@ -1132,7 +1139,9 @@ public class ParentChildTest extends LegacyTestCase {
|
|||
assertTrue( s.getCurrentLockMode(s3)==LockMode.UPGRADE );
|
||||
s.lock(s1, LockMode.UPGRADE_NOWAIT);
|
||||
s.lock(s4, LockMode.NONE);
|
||||
s.lock(s5, LockMode.UPGRADE_SKIPLOCKED);
|
||||
assertTrue( s.getCurrentLockMode(s4)==LockMode.UPGRADE_NOWAIT );
|
||||
assertTrue( s.getCurrentLockMode(s5)==LockMode.UPGRADE_SKIPLOCKED );
|
||||
|
||||
tx.commit();
|
||||
tx = s.beginTransaction();
|
||||
|
@ -1141,6 +1150,7 @@ public class ParentChildTest extends LegacyTestCase {
|
|||
assertTrue( s.getCurrentLockMode(s1)==LockMode.NONE );
|
||||
assertTrue( s.getCurrentLockMode(s2)==LockMode.NONE );
|
||||
assertTrue( s.getCurrentLockMode(s4)==LockMode.NONE );
|
||||
assertTrue( s.getCurrentLockMode(s5)==LockMode.NONE );
|
||||
|
||||
s.lock(s1, LockMode.READ); //upgrade
|
||||
assertTrue( s.getCurrentLockMode(s1)==LockMode.READ );
|
||||
|
@ -1162,8 +1172,9 @@ public class ParentChildTest extends LegacyTestCase {
|
|||
assertTrue( s.getCurrentLockMode(s1)==LockMode.NONE );
|
||||
assertTrue( s.getCurrentLockMode(s2)==LockMode.NONE );
|
||||
assertTrue( s.getCurrentLockMode(s4)==LockMode.NONE );
|
||||
assertTrue( s.getCurrentLockMode(s5)==LockMode.NONE );
|
||||
|
||||
s.delete(s1); s.delete(s2); s.delete(s3); s.delete(s4);
|
||||
s.delete(s1); s.delete(s2); s.delete(s3); s.delete(s4); s.delete(s5);
|
||||
tx.commit();
|
||||
s.close();
|
||||
}
|
||||
|
|
|
@ -285,7 +285,10 @@ public abstract class AbstractEntityManagerImpl implements HibernateEntityManage
|
|||
throw new PersistenceException( "Unable to parse " + AvailableSettings.LOCK_TIMEOUT + ": " + lockTimeout );
|
||||
}
|
||||
if ( timeoutSet ) {
|
||||
if ( timeout < 0 ) {
|
||||
if ( timeout == LockOptions.SKIP_LOCKED ) {
|
||||
options.setTimeOut( LockOptions.SKIP_LOCKED );
|
||||
}
|
||||
else if ( timeout < 0 ) {
|
||||
options.setTimeOut( LockOptions.WAIT_FOREVER );
|
||||
}
|
||||
else if ( timeout == 0 ) {
|
||||
|
|
Loading…
Reference in New Issue