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:
Vlad Mihalcea 2016-06-08 15:52:51 +03:00
parent 3d74c45e1d
commit a599d4fc1d
15 changed files with 826 additions and 18 deletions

View File

@ -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',

View File

@ -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

View File

@ -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() );
}

View File

@ -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?

View File

@ -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";

View File

@ -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;

View File

@ -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";
}
}

View File

@ -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 );
}
}

View File

@ -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;
}
}

View File

@ -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 )
)
);
}
}

View File

@ -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 )
)
);
}
}

View File

@ -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 )
)
);
}
}

View File

@ -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();
}
}
}

View File

@ -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 );
}
}
}

View File

@ -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;
}
}