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'
],
mariadb : [
'db.dialect' : 'org.hibernate.dialect.MariaDB102Dialect',
'db.dialect' : '',
// 'db.dialect' : 'org.hibernate.dialect.MariaDB102Dialect',
'jdbc.driver': 'org.mariadb.jdbc.Driver',
'jdbc.user' : 'hibernate_orm_test',
'jdbc.pass' : 'hibernate_orm_test',

View File

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

View File

@ -7,11 +7,12 @@
package org.hibernate.dialect;
import org.hibernate.LockOptions;
import org.hibernate.dialect.function.StandardSQLFunction;
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
*/
@ -58,4 +59,27 @@ public class MariaDB103Dialect extends MariaDB102Dialect {
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.NullPrecedence;
import org.hibernate.PessimisticLockException;
import org.hibernate.boot.TempTableDdlTransactionHandling;
import org.hibernate.cfg.Environment;
import org.hibernate.dialect.function.NoArgSQLFunction;
@ -525,6 +526,16 @@ public class MySQLDialect extends Dialect {
return new SQLExceptionConversionDelegate() {
@Override
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 );
if ( "41000".equals( sqlState ) ) {

View File

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

View File

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