HHH-8786 - find, refresh, lock should throw LockTimeoutException or PessimisticLockException when lock problems occur

HHH-12570 - MariaDB 10.3 adds support for lock timeouts via WAIT plus NOWAIT
This commit is contained in:
Steve Ebersole 2018-05-14 12:08:06 -05:00
parent 1570c71833
commit 9f4ff8ae90
7 changed files with 47 additions and 13 deletions

View File

@ -59,7 +59,8 @@ ext {
'jdbc.url' : 'jdbc:mysql://127.0.0.1/hibernate_orm_test' 'jdbc.url' : 'jdbc:mysql://127.0.0.1/hibernate_orm_test'
], ],
mariadb : [ mariadb : [
'db.dialect' : 'org.hibernate.dialect.MariaDB102Dialect', 'db.dialect' : '',
// 'db.dialect' : 'org.hibernate.dialect.MariaDB102Dialect',
'jdbc.driver': 'org.mariadb.jdbc.Driver', 'jdbc.driver': 'org.mariadb.jdbc.Driver',
'jdbc.user' : 'hibernate_orm_test', 'jdbc.user' : 'hibernate_orm_test',
'jdbc.pass' : 'hibernate_orm_test', 'jdbc.pass' : 'hibernate_orm_test',

View File

@ -207,6 +207,7 @@ tasks.withType( Test.class ).all { task ->
} }
processTestResources { processTestResources {
inputs.property( "db", db )
doLast { doLast {
copy { copy {
from( sourceSets.test.java.srcDirs ) { from( sourceSets.test.java.srcDirs ) {

View File

@ -7,11 +7,12 @@
package org.hibernate.dialect; package org.hibernate.dialect;
import org.hibernate.LockOptions;
import org.hibernate.dialect.function.StandardSQLFunction; import org.hibernate.dialect.function.StandardSQLFunction;
import org.hibernate.type.StandardBasicTypes; import org.hibernate.type.StandardBasicTypes;
/** /**
* An SQL dialect for MariaDB 10.3 and later, provides sequence support. * An SQL dialect for MariaDB 10.3 and later, provides sequence support, lock-timeouts, etc.
* *
* @author Philippe Marschall * @author Philippe Marschall
*/ */
@ -58,4 +59,27 @@ public class MariaDB103Dialect extends MariaDB102Dialect {
return "select table_name from information_schema.TABLES where table_type='SEQUENCE'"; return "select table_name from information_schema.TABLES where table_type='SEQUENCE'";
} }
@Override
public String getWriteLockString(int timeout) {
if ( timeout == LockOptions.NO_WAIT ) {
return getForUpdateNowaitString();
}
if ( timeout > 0 ) {
return getForUpdateString() + " wait " + timeout;
}
return getForUpdateString();
}
@Override
public String getForUpdateNowaitString() {
return getForUpdateString() + " nowait";
}
@Override
public String getForUpdateNowaitString(String aliases) {
return getForUpdateString( aliases ) + " nowait";
}
} }

View File

@ -13,6 +13,7 @@ import java.sql.Types;
import org.hibernate.JDBCException; import org.hibernate.JDBCException;
import org.hibernate.NullPrecedence; import org.hibernate.NullPrecedence;
import org.hibernate.PessimisticLockException;
import org.hibernate.boot.TempTableDdlTransactionHandling; import org.hibernate.boot.TempTableDdlTransactionHandling;
import org.hibernate.cfg.Environment; import org.hibernate.cfg.Environment;
import org.hibernate.dialect.function.NoArgSQLFunction; import org.hibernate.dialect.function.NoArgSQLFunction;
@ -525,6 +526,16 @@ public class MySQLDialect extends Dialect {
return new SQLExceptionConversionDelegate() { return new SQLExceptionConversionDelegate() {
@Override @Override
public JDBCException convert(SQLException sqlException, String message, String sql) { public JDBCException convert(SQLException sqlException, String message, String sql) {
switch ( sqlException.getErrorCode() ) {
case 1205: {
return new PessimisticLockException( message, sqlException, sql );
}
case 1207:
case 1206: {
return new LockAcquisitionException( message, sqlException, sql );
}
}
final String sqlState = JdbcExceptionHelper.extractSqlState( sqlException ); final String sqlState = JdbcExceptionHelper.extractSqlState( sqlException );
if ( "41000".equals( sqlState ) ) { if ( "41000".equals( sqlState ) ) {

View File

@ -8,7 +8,6 @@ package org.hibernate.internal;
import java.io.Serializable; import java.io.Serializable;
import java.sql.SQLException; import java.sql.SQLException;
import javax.persistence.EntityExistsException; import javax.persistence.EntityExistsException;
import javax.persistence.EntityNotFoundException; import javax.persistence.EntityNotFoundException;
import javax.persistence.LockTimeoutException; import javax.persistence.LockTimeoutException;
@ -34,6 +33,7 @@ import org.hibernate.dialect.lock.OptimisticEntityLockException;
import org.hibernate.dialect.lock.PessimisticEntityLockException; import org.hibernate.dialect.lock.PessimisticEntityLockException;
import org.hibernate.engine.spi.ExceptionConverter; import org.hibernate.engine.spi.ExceptionConverter;
import org.hibernate.engine.spi.SharedSessionContractImplementor; import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.exception.LockAcquisitionException;
import org.hibernate.loader.MultipleBagFetchException; import org.hibernate.loader.MultipleBagFetchException;
/** /**
@ -89,12 +89,12 @@ public class ExceptionConverterImpl implements ExceptionConverter {
handlePersistenceException( converted ); handlePersistenceException( converted );
return converted; return converted;
} }
else if ( cause instanceof LockingStrategyException ) { else if ( cause instanceof LockAcquisitionException ) {
final PersistenceException converted = wrapLockException( (HibernateException) cause, lockOptions ); final PersistenceException converted = wrapLockException( (HibernateException) cause, lockOptions );
handlePersistenceException( converted ); handlePersistenceException( converted );
return converted; return converted;
} }
else if ( cause instanceof org.hibernate.exception.LockTimeoutException ) { else if ( cause instanceof LockingStrategyException ) {
final PersistenceException converted = wrapLockException( (HibernateException) cause, lockOptions ); final PersistenceException converted = wrapLockException( (HibernateException) cause, lockOptions );
handlePersistenceException( converted ); handlePersistenceException( converted );
return converted; return converted;

View File

@ -69,11 +69,11 @@ public class ForUpdateFragment {
} }
} }
if ( upgradeType == LockMode.UPGRADE_NOWAIT ) { if ( upgradeType == LockMode.UPGRADE_NOWAIT || lockOptions.getTimeOut() == LockOptions.NO_WAIT ) {
setNowaitEnabled( true ); setNowaitEnabled( true );
} }
if ( upgradeType == LockMode.UPGRADE_SKIPLOCKED ) { if ( upgradeType == LockMode.UPGRADE_SKIPLOCKED || lockOptions.getTimeOut() == LockOptions.SKIP_LOCKED ) {
setSkipLockedEnabled( true ); setSkipLockedEnabled( true );
} }
} }

View File

@ -14,11 +14,8 @@ import javax.persistence.PessimisticLockException;
import org.hibernate.LockOptions; import org.hibernate.LockOptions;
import org.hibernate.cfg.AvailableSettings; import org.hibernate.cfg.AvailableSettings;
import org.hibernate.cfg.Configuration; import org.hibernate.cfg.Configuration;
import org.hibernate.dialect.MariaDBDialect;
import org.hibernate.dialect.SQLServerDialect; import org.hibernate.dialect.SQLServerDialect;
import org.hibernate.testing.SkipForDialect;
import org.hibernate.testing.SkipForDialects;
import org.hibernate.testing.TestForIssue; import org.hibernate.testing.TestForIssue;
import org.hibernate.testing.jdbc.SQLServerSnapshotIsolationConnectionProvider; import org.hibernate.testing.jdbc.SQLServerSnapshotIsolationConnectionProvider;
import org.hibernate.testing.transaction.TransactionUtil2; import org.hibernate.testing.transaction.TransactionUtil2;
@ -31,9 +28,6 @@ import static org.junit.Assert.fail;
/** /**
* @author Steve Ebersole * @author Steve Ebersole
*/ */
@SkipForDialects(
@SkipForDialect( value = MariaDBDialect.class, jiraKey = "HHH-8786", comment = "https://hibernate.atlassian.net/browse/HHH-8786")
)
public class LockExceptionTests extends AbstractJPATest { public class LockExceptionTests extends AbstractJPATest {
@Override @Override
public void configure(Configuration cfg) { public void configure(Configuration cfg) {
@ -77,6 +71,9 @@ public class LockExceptionTests extends AbstractJPATest {
} }
); );
} }
catch (Exception e) {
e.printStackTrace();
}
finally { finally {
inTransaction( inTransaction(
session -> session.createQuery( "delete Item" ).executeUpdate() session -> session.createQuery( "delete Item" ).executeUpdate()