HHH-10797 - PostgreSQL81Dialect does not honor the lock timeout settings
HHH-10799 - Add PostgreSQL 9.5 Dialect which supports the SKIP LOCKED clause HHH-10816 - SQLServer2005Dialect does not use NOWAIT for aliases HHH-10817 - AbstractHANADialect should support the NOWAIT directive in the FOR UPDATE clause
This commit is contained in:
parent
3d74c45e1d
commit
a599d4fc1d
|
@ -31,7 +31,7 @@ ext {
|
|||
'jdbc.url' : 'jdbc:derby:target/tmp/derby/hibernate_orm_test;databaseName=hibernate_orm_test;create=true'
|
||||
],
|
||||
pgsql : [
|
||||
'db.dialect' : 'org.hibernate.dialect.PostgreSQL94Dialect',
|
||||
'db.dialect' : 'org.hibernate.dialect.PostgreSQL95Dialect',
|
||||
'jdbc.driver': 'org.postgresql.Driver',
|
||||
'jdbc.user' : 'hibernate_orm_test',
|
||||
'jdbc.pass' : 'hibernate_orm_test',
|
||||
|
|
|
@ -490,7 +490,30 @@ public abstract class AbstractHANADialect extends Dialect {
|
|||
return getForUpdateString( lockMode );
|
||||
}
|
||||
|
||||
return getForUpdateString( lockMode ) + " of " + aliases;
|
||||
String clause = getForUpdateString( lockMode ) + " of " + aliases;
|
||||
if(lockOptions.getTimeOut() == LockOptions.NO_WAIT) {
|
||||
clause += " nowait";
|
||||
}
|
||||
return clause;
|
||||
}
|
||||
|
||||
public String getForUpdateNowaitString() {
|
||||
return getForUpdateString() + " nowait";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getReadLockString(int timeout) {
|
||||
return getWriteLockString( timeout );
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getWriteLockString(int timeout) {
|
||||
if ( timeout == LockOptions.NO_WAIT ) {
|
||||
return getForUpdateNowaitString();
|
||||
}
|
||||
else {
|
||||
return getForUpdateString();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -170,7 +170,7 @@ abstract class AbstractTransactSQLDialect extends Dialect {
|
|||
}
|
||||
|
||||
if ( start > -1 ) {
|
||||
final String lockHint = appendLockHint( lockMode, alias );
|
||||
final String lockHint = appendLockHint( aliasedLockOptions, alias );
|
||||
buffer.replace( start, end, lockHint );
|
||||
correction += ( lockHint.length() - alias.length() );
|
||||
}
|
||||
|
|
|
@ -1228,6 +1228,22 @@ public abstract class Dialect implements ConversionContext {
|
|||
|
||||
/**
|
||||
* Get the string to append to SELECT statements to acquire WRITE locks
|
||||
* for this dialect given the aliases of the columns to be write locked.
|
||||
* Location of the of the returned string is treated
|
||||
* the same as getForUpdateString.
|
||||
*
|
||||
* @param aliases The columns to be read locked.
|
||||
* @param timeout in milliseconds, -1 for indefinite wait and 0 for no wait.
|
||||
* @return The appropriate <tt>LOCK</tt> clause string.
|
||||
*/
|
||||
public String getWriteLockString(String aliases, int timeout) {
|
||||
// by default we simply return the getWriteLockString(timeout) result since
|
||||
// the default is to say no support for "FOR UPDATE OF ..."
|
||||
return getWriteLockString(timeout);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the string to append to SELECT statements to acquire READ locks
|
||||
* for this dialect. Location of the of the returned string is treated
|
||||
* the same as getForUpdateString.
|
||||
*
|
||||
|
@ -1238,6 +1254,21 @@ public abstract class Dialect implements ConversionContext {
|
|||
return getForUpdateString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the string to append to SELECT statements to acquire READ locks
|
||||
* for this dialect given the aliases of the columns to be read locked.
|
||||
* Location of the of the returned string is treated
|
||||
* the same as getForUpdateString.
|
||||
*
|
||||
* @param aliases The columns to be read locked.
|
||||
* @param timeout in milliseconds, -1 for indefinite wait and 0 for no wait.
|
||||
* @return The appropriate <tt>LOCK</tt> clause string.
|
||||
*/
|
||||
public String getReadLockString(String aliases, int timeout) {
|
||||
// by default we simply return the getReadLockString(timeout) result since
|
||||
// the default is to say no support for "FOR UPDATE OF ..."
|
||||
return getReadLockString(timeout);
|
||||
}
|
||||
|
||||
/**
|
||||
* Is <tt>FOR UPDATE OF</tt> syntax supported?
|
||||
|
|
|
@ -50,6 +50,16 @@ public class Oracle10gDialect extends Oracle9iDialect {
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getWriteLockString(String aliases, int timeout) {
|
||||
if ( timeout == LockOptions.SKIP_LOCKED ) {
|
||||
return getForUpdateSkipLockedString( aliases );
|
||||
}
|
||||
else {
|
||||
return super.getWriteLockString( aliases, timeout );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getForUpdateSkipLockedString() {
|
||||
return " for update skip locked";
|
||||
|
|
|
@ -6,6 +6,13 @@
|
|||
*/
|
||||
package org.hibernate.dialect;
|
||||
|
||||
import java.sql.CallableStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Types;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
|
||||
import org.hibernate.JDBCException;
|
||||
import org.hibernate.LockMode;
|
||||
import org.hibernate.LockOptions;
|
||||
|
@ -39,13 +46,6 @@ import org.hibernate.type.descriptor.sql.BlobTypeDescriptor;
|
|||
import org.hibernate.type.descriptor.sql.ClobTypeDescriptor;
|
||||
import org.hibernate.type.descriptor.sql.SqlTypeDescriptor;
|
||||
|
||||
import java.sql.CallableStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Types;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* An SQL dialect for Postgres
|
||||
* <p/>
|
||||
|
@ -288,7 +288,23 @@ public class PostgreSQL81Dialect extends Dialect {
|
|||
}
|
||||
}
|
||||
}
|
||||
return getForUpdateString( aliases );
|
||||
LockMode lockMode = lockOptions.getLockMode();
|
||||
switch ( lockMode ) {
|
||||
case UPGRADE:
|
||||
return getForUpdateString(aliases);
|
||||
case PESSIMISTIC_READ:
|
||||
return getReadLockString( aliases, lockOptions.getTimeOut() );
|
||||
case PESSIMISTIC_WRITE:
|
||||
return getWriteLockString( aliases, lockOptions.getTimeOut() );
|
||||
case UPGRADE_NOWAIT:
|
||||
case FORCE:
|
||||
case PESSIMISTIC_FORCE_INCREMENT:
|
||||
return getForUpdateNowaitString(aliases);
|
||||
case UPGRADE_SKIPLOCKED:
|
||||
return getForUpdateSkipLockedString(aliases);
|
||||
default:
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -509,6 +525,16 @@ public class PostgreSQL81Dialect extends Dialect {
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getWriteLockString(String aliases, int timeout) {
|
||||
if ( timeout == LockOptions.NO_WAIT ) {
|
||||
return String.format( " for update of %s nowait", aliases );
|
||||
}
|
||||
else {
|
||||
return " for update of " + aliases;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getReadLockString(int timeout) {
|
||||
if ( timeout == LockOptions.NO_WAIT ) {
|
||||
|
@ -519,6 +545,16 @@ public class PostgreSQL81Dialect extends Dialect {
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getReadLockString(String aliases, int timeout) {
|
||||
if ( timeout == LockOptions.NO_WAIT ) {
|
||||
return String.format( " for share of %s nowait", aliases );
|
||||
}
|
||||
else {
|
||||
return " for share of " + aliases;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsRowValueConstructorSyntax() {
|
||||
return true;
|
||||
|
|
|
@ -0,0 +1,65 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
*/
|
||||
package org.hibernate.dialect;
|
||||
|
||||
import org.hibernate.LockOptions;
|
||||
|
||||
/**
|
||||
* An SQL dialect for Postgres 9.5 and later. Adds support for SKIP LOCKED.
|
||||
*/
|
||||
public class PostgreSQL95Dialect extends PostgreSQL94Dialect {
|
||||
|
||||
@Override
|
||||
public String getWriteLockString(int timeout) {
|
||||
if ( timeout == LockOptions.SKIP_LOCKED ) {
|
||||
return getForUpdateSkipLockedString();
|
||||
}
|
||||
else {
|
||||
return super.getWriteLockString( timeout );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getWriteLockString(String aliases, int timeout) {
|
||||
if ( timeout == LockOptions.SKIP_LOCKED ) {
|
||||
return getForUpdateSkipLockedString( aliases );
|
||||
}
|
||||
else {
|
||||
return super.getWriteLockString( aliases, timeout );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getReadLockString(int timeout) {
|
||||
if ( timeout == LockOptions.SKIP_LOCKED ) {
|
||||
return " for share skip locked";
|
||||
}
|
||||
else {
|
||||
return super.getReadLockString( timeout );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getReadLockString(String aliases, int timeout) {
|
||||
if ( timeout == LockOptions.SKIP_LOCKED ) {
|
||||
return String.format( " for share of %s skip locked", aliases );
|
||||
}
|
||||
else {
|
||||
return super.getReadLockString( aliases, timeout );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getForUpdateSkipLockedString() {
|
||||
return " for update skip locked";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getForUpdateSkipLockedString(String aliases) {
|
||||
return getForUpdateString() + " of " + aliases + " skip locked";
|
||||
}
|
||||
}
|
|
@ -8,15 +8,15 @@ package org.hibernate.test.dialect.unit.lockhint;
|
|||
|
||||
import java.util.Collections;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.hibernate.LockMode;
|
||||
import org.hibernate.LockOptions;
|
||||
import org.hibernate.dialect.Dialect;
|
||||
import org.hibernate.internal.util.StringHelper;
|
||||
|
||||
import org.hibernate.testing.junit4.BaseUnitTestCase;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
|
@ -46,6 +46,12 @@ public abstract class AbstractLockHintTest extends BaseUnitTestCase {
|
|||
new SyntaxChecker( "select xyz from ABC $HOLDER$, DEF d", "a" ).verify();
|
||||
}
|
||||
|
||||
protected LockOptions lockOptions(String aliasToLock) {
|
||||
LockOptions lockOptions = new LockOptions(LockMode.UPGRADE);
|
||||
lockOptions.setAliasSpecificLockMode( aliasToLock, LockMode.UPGRADE );
|
||||
return lockOptions;
|
||||
}
|
||||
|
||||
protected class SyntaxChecker {
|
||||
private final String aliasToLock;
|
||||
private final String rawSql;
|
||||
|
@ -62,9 +68,7 @@ public abstract class AbstractLockHintTest extends BaseUnitTestCase {
|
|||
}
|
||||
|
||||
public void verify() {
|
||||
LockOptions lockOptions = new LockOptions(LockMode.UPGRADE);
|
||||
lockOptions.setAliasSpecificLockMode( aliasToLock, LockMode.UPGRADE );
|
||||
String actualProcessedSql = dialect.applyLocksToSql( rawSql, lockOptions, Collections.EMPTY_MAP );
|
||||
String actualProcessedSql = dialect.applyLocksToSql( rawSql, lockOptions( aliasToLock ), Collections.EMPTY_MAP );
|
||||
assertEquals( expectedProcessedSql, actualProcessedSql );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,34 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
*/
|
||||
package org.hibernate.test.dialect.unit.lockhint;
|
||||
|
||||
import org.hibernate.LockMode;
|
||||
import org.hibernate.LockOptions;
|
||||
import org.hibernate.dialect.Dialect;
|
||||
import org.hibernate.dialect.SQLServer2005Dialect;
|
||||
|
||||
/**
|
||||
* @author Vlad Mihalcea
|
||||
*/
|
||||
public class SQLServer2005LockHintsTest extends AbstractLockHintTest {
|
||||
public static final Dialect DIALECT = new SQLServer2005Dialect();
|
||||
|
||||
protected String getLockHintUsed() {
|
||||
return "with (updlock, rowlock, nowait)";
|
||||
}
|
||||
|
||||
protected Dialect getDialectUnderTest() {
|
||||
return DIALECT;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected LockOptions lockOptions(String aliasToLock) {
|
||||
LockOptions lockOptions = new LockOptions( LockMode.PESSIMISTIC_WRITE).setTimeOut( LockOptions.NO_WAIT );
|
||||
lockOptions.setAliasSpecificLockMode( aliasToLock, LockMode.PESSIMISTIC_WRITE );
|
||||
return lockOptions;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,148 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
*/
|
||||
package org.hibernate.test.dialect.unit.locktimeout;
|
||||
|
||||
import org.hibernate.LockMode;
|
||||
import org.hibernate.LockOptions;
|
||||
import org.hibernate.dialect.Dialect;
|
||||
import org.hibernate.dialect.HANARowStoreDialect;
|
||||
|
||||
import org.hibernate.testing.junit4.BaseUnitTestCase;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
/**
|
||||
* Expected lock clauses according to the official HANA FOR UPDATE clause documentation:
|
||||
*
|
||||
* https://help.sap.com/saphelp_hanaplatform/helpdata/en/20/fcf24075191014a89e9dc7b8408b26/content.htm#loio20fcf24075191014a89e9dc7b8408b26__sql_select_1sql_select_for_update
|
||||
*
|
||||
* @author Vlad Mihalcea
|
||||
*/
|
||||
public class HANALockTimeoutTest extends BaseUnitTestCase {
|
||||
|
||||
private final Dialect dialect = new HANARowStoreDialect();
|
||||
|
||||
@Test
|
||||
public void testLockTimeoutNoAliasNoTimeout() {
|
||||
assertEquals(
|
||||
" for update",
|
||||
dialect.getForUpdateString( new LockOptions( LockMode.PESSIMISTIC_READ ) )
|
||||
);
|
||||
assertEquals(
|
||||
" for update",
|
||||
dialect.getForUpdateString( new LockOptions( LockMode.PESSIMISTIC_WRITE ) )
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLockTimeoutNoAliasNoWait() {
|
||||
assertEquals(
|
||||
" for update nowait",
|
||||
dialect.getForUpdateString( new LockOptions( LockMode.PESSIMISTIC_READ )
|
||||
.setTimeOut( LockOptions.NO_WAIT ) )
|
||||
);
|
||||
assertEquals(
|
||||
" for update nowait",
|
||||
dialect.getForUpdateString( new LockOptions( LockMode.PESSIMISTIC_WRITE )
|
||||
.setTimeOut( LockOptions.NO_WAIT ) )
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLockTimeoutNoAliasSkipLocked() {
|
||||
assertEquals(
|
||||
" for update",
|
||||
dialect.getForUpdateString( new LockOptions( LockMode.PESSIMISTIC_READ )
|
||||
.setTimeOut( LockOptions.SKIP_LOCKED ) )
|
||||
);
|
||||
assertEquals(
|
||||
" for update",
|
||||
dialect.getForUpdateString( new LockOptions( LockMode.PESSIMISTIC_WRITE )
|
||||
.setTimeOut( LockOptions.SKIP_LOCKED ) )
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLockTimeoutAliasNoTimeout() {
|
||||
String alias = "a";
|
||||
assertEquals(
|
||||
" for update of a",
|
||||
dialect.getForUpdateString(
|
||||
alias,
|
||||
new LockOptions( LockMode.PESSIMISTIC_READ ).setAliasSpecificLockMode(
|
||||
alias,
|
||||
LockMode.PESSIMISTIC_READ
|
||||
)
|
||||
)
|
||||
);
|
||||
assertEquals(
|
||||
" for update of a",
|
||||
dialect.getForUpdateString(
|
||||
alias,
|
||||
new LockOptions( LockMode.PESSIMISTIC_WRITE ).setAliasSpecificLockMode(
|
||||
alias,
|
||||
LockMode.PESSIMISTIC_WRITE
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLockTimeoutAliasNoWait() {
|
||||
String alias = "a";
|
||||
assertEquals(
|
||||
" for update of a nowait",
|
||||
dialect.getForUpdateString(
|
||||
alias,
|
||||
new LockOptions( LockMode.PESSIMISTIC_READ ).setAliasSpecificLockMode(
|
||||
alias,
|
||||
LockMode.PESSIMISTIC_READ
|
||||
)
|
||||
.setTimeOut( LockOptions.NO_WAIT )
|
||||
)
|
||||
);
|
||||
assertEquals(
|
||||
" for update of a nowait",
|
||||
dialect.getForUpdateString(
|
||||
alias,
|
||||
new LockOptions( LockMode.PESSIMISTIC_WRITE ).setAliasSpecificLockMode(
|
||||
alias,
|
||||
LockMode.PESSIMISTIC_WRITE
|
||||
)
|
||||
.setTimeOut( LockOptions.NO_WAIT )
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLockTimeoutAliasSkipLocked() {
|
||||
String alias = "a";
|
||||
assertEquals(
|
||||
" for update of a",
|
||||
dialect.getForUpdateString(
|
||||
alias,
|
||||
new LockOptions( LockMode.PESSIMISTIC_READ ).setAliasSpecificLockMode(
|
||||
alias,
|
||||
LockMode.PESSIMISTIC_READ
|
||||
)
|
||||
.setTimeOut( LockOptions.SKIP_LOCKED )
|
||||
)
|
||||
);
|
||||
assertEquals(
|
||||
" for update of a",
|
||||
dialect.getForUpdateString(
|
||||
alias,
|
||||
new LockOptions( LockMode.PESSIMISTIC_WRITE ).setAliasSpecificLockMode(
|
||||
alias,
|
||||
LockMode.PESSIMISTIC_WRITE
|
||||
)
|
||||
.setTimeOut( LockOptions.SKIP_LOCKED )
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,144 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
*/
|
||||
package org.hibernate.test.dialect.unit.locktimeout;
|
||||
|
||||
import org.hibernate.LockMode;
|
||||
import org.hibernate.LockOptions;
|
||||
import org.hibernate.dialect.Dialect;
|
||||
import org.hibernate.dialect.Oracle12cDialect;
|
||||
|
||||
import org.hibernate.testing.junit4.BaseUnitTestCase;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
/**
|
||||
* @author Vlad Mihalcea
|
||||
*/
|
||||
public class OracleLockTimeoutTest extends BaseUnitTestCase {
|
||||
|
||||
private final Dialect dialect = new Oracle12cDialect();
|
||||
|
||||
@Test
|
||||
public void testLockTimeoutNoAliasNoTimeout() {
|
||||
assertEquals(
|
||||
" for update",
|
||||
dialect.getForUpdateString( new LockOptions( LockMode.PESSIMISTIC_READ ) )
|
||||
);
|
||||
assertEquals(
|
||||
" for update",
|
||||
dialect.getForUpdateString( new LockOptions( LockMode.PESSIMISTIC_WRITE ) )
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLockTimeoutNoAliasNoWait() {
|
||||
assertEquals(
|
||||
" for update nowait",
|
||||
dialect.getForUpdateString( new LockOptions( LockMode.PESSIMISTIC_READ )
|
||||
.setTimeOut( LockOptions.NO_WAIT ) )
|
||||
);
|
||||
assertEquals(
|
||||
" for update nowait",
|
||||
dialect.getForUpdateString( new LockOptions( LockMode.PESSIMISTIC_WRITE )
|
||||
.setTimeOut( LockOptions.NO_WAIT ) )
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLockTimeoutNoAliasSkipLocked() {
|
||||
assertEquals(
|
||||
" for update skip locked",
|
||||
dialect.getForUpdateString( new LockOptions( LockMode.PESSIMISTIC_READ )
|
||||
.setTimeOut( LockOptions.SKIP_LOCKED ) )
|
||||
);
|
||||
assertEquals(
|
||||
" for update skip locked",
|
||||
dialect.getForUpdateString( new LockOptions( LockMode.PESSIMISTIC_WRITE )
|
||||
.setTimeOut( LockOptions.SKIP_LOCKED ) )
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLockTimeoutAliasNoTimeout() {
|
||||
String alias = "a";
|
||||
assertEquals(
|
||||
" for update",
|
||||
dialect.getForUpdateString(
|
||||
alias,
|
||||
new LockOptions( LockMode.PESSIMISTIC_READ ).setAliasSpecificLockMode(
|
||||
alias,
|
||||
LockMode.PESSIMISTIC_READ
|
||||
)
|
||||
)
|
||||
);
|
||||
assertEquals(
|
||||
" for update",
|
||||
dialect.getForUpdateString(
|
||||
alias,
|
||||
new LockOptions( LockMode.PESSIMISTIC_WRITE ).setAliasSpecificLockMode(
|
||||
alias,
|
||||
LockMode.PESSIMISTIC_WRITE
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLockTimeoutAliasNoWait() {
|
||||
String alias = "a";
|
||||
assertEquals(
|
||||
" for update nowait",
|
||||
dialect.getForUpdateString(
|
||||
alias,
|
||||
new LockOptions( LockMode.PESSIMISTIC_READ ).setAliasSpecificLockMode(
|
||||
alias,
|
||||
LockMode.PESSIMISTIC_READ
|
||||
)
|
||||
.setTimeOut( LockOptions.NO_WAIT )
|
||||
)
|
||||
);
|
||||
assertEquals(
|
||||
" for update nowait",
|
||||
dialect.getForUpdateString(
|
||||
alias,
|
||||
new LockOptions( LockMode.PESSIMISTIC_WRITE ).setAliasSpecificLockMode(
|
||||
alias,
|
||||
LockMode.PESSIMISTIC_WRITE
|
||||
)
|
||||
.setTimeOut( LockOptions.NO_WAIT )
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLockTimeoutAliasSkipLocked() {
|
||||
String alias = "a";
|
||||
assertEquals(
|
||||
" for update skip locked",
|
||||
dialect.getForUpdateString(
|
||||
alias,
|
||||
new LockOptions( LockMode.PESSIMISTIC_READ ).setAliasSpecificLockMode(
|
||||
alias,
|
||||
LockMode.PESSIMISTIC_READ
|
||||
)
|
||||
.setTimeOut( LockOptions.SKIP_LOCKED )
|
||||
)
|
||||
);
|
||||
assertEquals(
|
||||
" for update skip locked",
|
||||
dialect.getForUpdateString(
|
||||
alias,
|
||||
new LockOptions( LockMode.PESSIMISTIC_WRITE ).setAliasSpecificLockMode(
|
||||
alias,
|
||||
LockMode.PESSIMISTIC_WRITE
|
||||
)
|
||||
.setTimeOut( LockOptions.SKIP_LOCKED )
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,144 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
*/
|
||||
package org.hibernate.test.dialect.unit.locktimeout;
|
||||
|
||||
import org.hibernate.LockMode;
|
||||
import org.hibernate.LockOptions;
|
||||
import org.hibernate.dialect.Dialect;
|
||||
import org.hibernate.dialect.PostgreSQL95Dialect;
|
||||
|
||||
import org.hibernate.testing.junit4.BaseUnitTestCase;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
/**
|
||||
* @author Vlad Mihalcea
|
||||
*/
|
||||
public class PostgreSQLLockTimeoutTest extends BaseUnitTestCase {
|
||||
|
||||
private final Dialect dialect = new PostgreSQL95Dialect();
|
||||
|
||||
@Test
|
||||
public void testLockTimeoutNoAliasNoTimeout() {
|
||||
assertEquals(
|
||||
" for share",
|
||||
dialect.getForUpdateString( new LockOptions( LockMode.PESSIMISTIC_READ ) )
|
||||
);
|
||||
assertEquals(
|
||||
" for update",
|
||||
dialect.getForUpdateString( new LockOptions( LockMode.PESSIMISTIC_WRITE ) )
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLockTimeoutNoAliasNoWait() {
|
||||
assertEquals(
|
||||
" for share nowait",
|
||||
dialect.getForUpdateString( new LockOptions( LockMode.PESSIMISTIC_READ )
|
||||
.setTimeOut( LockOptions.NO_WAIT ) )
|
||||
);
|
||||
assertEquals(
|
||||
" for update nowait",
|
||||
dialect.getForUpdateString( new LockOptions( LockMode.PESSIMISTIC_WRITE )
|
||||
.setTimeOut( LockOptions.NO_WAIT ) )
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLockTimeoutNoAliasSkipLocked() {
|
||||
assertEquals(
|
||||
" for share skip locked",
|
||||
dialect.getForUpdateString( new LockOptions( LockMode.PESSIMISTIC_READ )
|
||||
.setTimeOut( LockOptions.SKIP_LOCKED ) )
|
||||
);
|
||||
assertEquals(
|
||||
" for update skip locked",
|
||||
dialect.getForUpdateString( new LockOptions( LockMode.PESSIMISTIC_WRITE )
|
||||
.setTimeOut( LockOptions.SKIP_LOCKED ) )
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLockTimeoutAliasNoTimeout() {
|
||||
String alias = "a";
|
||||
assertEquals(
|
||||
" for share of a",
|
||||
dialect.getForUpdateString(
|
||||
alias,
|
||||
new LockOptions( LockMode.PESSIMISTIC_READ ).setAliasSpecificLockMode(
|
||||
alias,
|
||||
LockMode.PESSIMISTIC_READ
|
||||
)
|
||||
)
|
||||
);
|
||||
assertEquals(
|
||||
" for update of a",
|
||||
dialect.getForUpdateString(
|
||||
alias,
|
||||
new LockOptions( LockMode.PESSIMISTIC_WRITE ).setAliasSpecificLockMode(
|
||||
alias,
|
||||
LockMode.PESSIMISTIC_WRITE
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLockTimeoutAliasNoWait() {
|
||||
String alias = "a";
|
||||
assertEquals(
|
||||
" for share of a nowait",
|
||||
dialect.getForUpdateString(
|
||||
alias,
|
||||
new LockOptions( LockMode.PESSIMISTIC_READ ).setAliasSpecificLockMode(
|
||||
alias,
|
||||
LockMode.PESSIMISTIC_READ
|
||||
)
|
||||
.setTimeOut( LockOptions.NO_WAIT )
|
||||
)
|
||||
);
|
||||
assertEquals(
|
||||
" for update of a nowait",
|
||||
dialect.getForUpdateString(
|
||||
alias,
|
||||
new LockOptions( LockMode.PESSIMISTIC_WRITE ).setAliasSpecificLockMode(
|
||||
alias,
|
||||
LockMode.PESSIMISTIC_WRITE
|
||||
)
|
||||
.setTimeOut( LockOptions.NO_WAIT )
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLockTimeoutAliasSkipLocked() {
|
||||
String alias = "a";
|
||||
assertEquals(
|
||||
" for share of a skip locked",
|
||||
dialect.getForUpdateString(
|
||||
alias,
|
||||
new LockOptions( LockMode.PESSIMISTIC_READ ).setAliasSpecificLockMode(
|
||||
alias,
|
||||
LockMode.PESSIMISTIC_READ
|
||||
)
|
||||
.setTimeOut( LockOptions.SKIP_LOCKED )
|
||||
)
|
||||
);
|
||||
assertEquals(
|
||||
" for update of a skip locked",
|
||||
dialect.getForUpdateString(
|
||||
alias,
|
||||
new LockOptions( LockMode.PESSIMISTIC_WRITE ).setAliasSpecificLockMode(
|
||||
alias,
|
||||
LockMode.PESSIMISTIC_WRITE
|
||||
)
|
||||
.setTimeOut( LockOptions.SKIP_LOCKED )
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,103 @@
|
|||
package org.hibernate.test.locking;
|
||||
|
||||
import org.hibernate.LockMode;
|
||||
import org.hibernate.LockOptions;
|
||||
import org.hibernate.Session;
|
||||
import org.hibernate.boot.SessionFactoryBuilder;
|
||||
import org.hibernate.dialect.Oracle8iDialect;
|
||||
import org.hibernate.dialect.PostgreSQL81Dialect;
|
||||
import org.hibernate.dialect.SQLServer2005Dialect;
|
||||
|
||||
import org.hibernate.testing.RequiresDialect;
|
||||
import org.hibernate.testing.junit4.BaseNonConfigCoreFunctionalTestCase;
|
||||
import org.hibernate.test.util.SQLStatementInterceptor;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
/**
|
||||
* @author Vlad Mihalcea
|
||||
*/
|
||||
@RequiresDialect({ Oracle8iDialect.class, PostgreSQL81Dialect.class} )
|
||||
public class PessimisticWriteLockTimeoutTest
|
||||
extends BaseNonConfigCoreFunctionalTestCase {
|
||||
|
||||
private SQLStatementInterceptor sqlStatementInterceptor;
|
||||
|
||||
@Override
|
||||
protected Class<?>[] getAnnotatedClasses() {
|
||||
return new Class[] { A.class };
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void configureSessionFactoryBuilder(SessionFactoryBuilder sfb) {
|
||||
sqlStatementInterceptor = new SQLStatementInterceptor( sfb );
|
||||
}
|
||||
|
||||
private A entity;
|
||||
|
||||
@Before
|
||||
public void createTestData() {
|
||||
Session session = sessionFactory().openSession();
|
||||
session.beginTransaction();
|
||||
try {
|
||||
entity = new A();
|
||||
session.persist( entity );
|
||||
}
|
||||
finally {
|
||||
session.getTransaction().commit();
|
||||
session.close();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@RequiresDialect({ Oracle8iDialect.class, PostgreSQL81Dialect.class,
|
||||
SQLServer2005Dialect.class } )
|
||||
public void testNoWait()
|
||||
throws NoSuchFieldException, IllegalAccessException {
|
||||
|
||||
Session session = sessionFactory().openSession();
|
||||
session.beginTransaction();
|
||||
try {
|
||||
session.createQuery(
|
||||
"select a from A a", A.class )
|
||||
.unwrap( org.hibernate.query.Query.class )
|
||||
.setLockOptions(
|
||||
new LockOptions( LockMode.PESSIMISTIC_WRITE )
|
||||
.setTimeOut( LockOptions.NO_WAIT ) )
|
||||
.list();
|
||||
|
||||
String lockingQuery = sqlStatementInterceptor.getSqlQueries().getLast();
|
||||
assertTrue( lockingQuery.toLowerCase().contains( "nowait") );
|
||||
}
|
||||
finally {
|
||||
session.getTransaction().commit();
|
||||
session.close();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSkipLocked()
|
||||
throws NoSuchFieldException, IllegalAccessException {
|
||||
|
||||
Session session = sessionFactory().openSession();
|
||||
session.beginTransaction();
|
||||
try {
|
||||
session.createQuery(
|
||||
"select a from A a", A.class )
|
||||
.unwrap( org.hibernate.query.Query.class )
|
||||
.setLockOptions(
|
||||
new LockOptions( LockMode.PESSIMISTIC_WRITE )
|
||||
.setTimeOut( LockOptions.SKIP_LOCKED ) )
|
||||
.list();
|
||||
|
||||
String lockingQuery = sqlStatementInterceptor.getSqlQueries().getLast();
|
||||
assertTrue( lockingQuery.toLowerCase().contains( "skip locked") );
|
||||
}
|
||||
finally {
|
||||
session.getTransaction().commit();
|
||||
session.close();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
package org.hibernate.test.util;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
|
||||
/**
|
||||
* @author Vlad Mihalcea
|
||||
*/
|
||||
public class ReflectionUtil {
|
||||
|
||||
/**
|
||||
* Get a field from a given class
|
||||
* @param clazz clazz
|
||||
* @param name field name
|
||||
* @return field object
|
||||
*/
|
||||
public static Field getField(Class clazz, String name) {
|
||||
try {
|
||||
Field field = clazz.getDeclaredField( name );
|
||||
field.setAccessible( true );
|
||||
return field;
|
||||
}
|
||||
catch ( NoSuchFieldException e ) {
|
||||
throw new IllegalArgumentException( "Class " + clazz + " does not contain a " + name + " field", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set target Object field to a certain value
|
||||
* @param target Object whose field is being set
|
||||
* @param field Object field to set
|
||||
* @param value the new value for the given field
|
||||
*/
|
||||
public static void setField(Object target, Field field, Object value) {
|
||||
try {
|
||||
field.set( target, value );
|
||||
}
|
||||
catch ( IllegalAccessException e ) {
|
||||
throw new IllegalArgumentException("Field " + field + " could not be set", e );
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
package org.hibernate.test.util;
|
||||
|
||||
import java.util.LinkedList;
|
||||
|
||||
import org.hibernate.boot.SessionFactoryBuilder;
|
||||
import org.hibernate.resource.jdbc.spi.StatementInspector;
|
||||
|
||||
/**
|
||||
* @author Vlad Mihalcea
|
||||
*/
|
||||
public class SQLStatementInterceptor {
|
||||
|
||||
private final LinkedList<String> sqlQueries = new LinkedList<>( );
|
||||
|
||||
public SQLStatementInterceptor(SessionFactoryBuilder sessionFactoryBuilder) {
|
||||
sessionFactoryBuilder.applyStatementInspector( (StatementInspector) sql -> {
|
||||
sqlQueries.add( sql );
|
||||
return sql;
|
||||
} );
|
||||
}
|
||||
|
||||
public LinkedList<String> getSqlQueries() {
|
||||
return sqlQueries;
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue