Mysql lock wait timeout





     前段时间遇到一个问题,有个事务内的代码,但是显然没有全部回滚,导致业务事务不完整;error message如下
org.springframework.dao.CannotAcquireLockException: 
### Error updating database.  Cause: com.mysql.cj.jdbc.exceptions.MySQLTransactionRollbackException: Lock wait timeout exceeded; try restarting transaction

   如上显示,遇到的MySQLTransactionRollbackException,触发原因是“锁等待超时”,从mysql connector中抛出,抛出位置的代码如下,可以看到

#SQLError.class
public static SQLException createSQLException(String message, String sqlState, int vendorErrorCode, boolean isTransient, Throwable cause,
            ExceptionInterceptor interceptor) {
        try {
            SQLException sqlEx = null;

            if (sqlState != null) {
                if (sqlState.startsWith("08")) {
                    if (isTransient) {
                        sqlEx = new SQLTransientConnectionException(message, sqlState, vendorErrorCode);
                    } else {
                        sqlEx = new SQLNonTransientConnectionException(message, sqlState, vendorErrorCode);
                    }

                } else if (sqlState.startsWith("22")) {
                    sqlEx = new SQLDataException(message, sqlState, vendorErrorCode);

                } else if (sqlState.startsWith("23")) {
                    sqlEx = new SQLIntegrityConstraintViolationException(message, sqlState, vendorErrorCode);

                } else if (sqlState.startsWith("42")) {
                    sqlEx = new SQLSyntaxErrorException(message, sqlState, vendorErrorCode);
                  //40开头的sqlstate都会抛出这个异常
                } else if (sqlState.startsWith("40")) {
                    sqlEx = new MySQLTransactionRollbackException(message, sqlState, vendorErrorCode);

                } else if (sqlState.startsWith("70100")) {
                    sqlEx = new MySQLQueryInterruptedException(message, sqlState, vendorErrorCode);

                } else {
                    sqlEx = new SQLException(message, sqlState, vendorErrorCode);
                }
            } else {
                sqlEx = new SQLException(message, sqlState, vendorErrorCode);
            }

            if (cause != null) {
                try {
                    sqlEx.initCause(cause);
                } catch (Throwable t) {
                    // we're not going to muck with that here, since it's an error condition anyway!
                }
            }

            return runThroughExceptionInterceptor(interceptor, sqlEx);

        } catch (Exception sqlEx) {
            SQLException unexpectedEx = new SQLException(
                    "Unable to create correct SQLException class instance, error class/codes may be incorrect. Reason: " + Util.stackTraceToString(sqlEx),
                    MysqlErrorNumbers.SQL_STATE_GENERAL_ERROR);

            return runThroughExceptionInterceptor(interceptor, unexpectedEx);

        }
    }

    在mysql connector文档中有如下表格





到这里有几个疑问,1.什么情况下会造成lock wait timeout?2.为什么lock timeout为什么事务不全部回滚?3.为什么这里的异常命名用MySQLTransactionRollbackException?





1.什么情况下会造成lock wait timeout?

mysql官网可以看得到关于lock wait timeout相关的配置如下,由于一行数据被另一个事务锁定,导致当下的事务一直等待,直至超时!(当然锁等待超时一般是不太容易的,要么是超时时间设置的太短,要么是代码逻辑上出现了死锁)




2.为什么lock timeout为什么事务不全部回滚?

继续往下看,可以知道mysql服务队锁等待超时的情况,不会回滚整个事务,如果需要锁等待超时回滚整个事务,需要配置参数innodb_rollback_on_timeout为true;(事实上现在的持久层框架,在遇到异常时,可以做到帮我们回滚整个事务,如spring的@Transactional注解)




3.为什么这里的异常命名用MySQLTransactionRollbackException?

我当初第一次看这个异常的名字,第一感觉是事务回滚过程中产生的异常,事实上,并不是。我翻阅相关文档,并没有任何解释,而且代码上也没有相关的注释,暂时只能不管他了!

Cause: com.mysql.cj.jdbc.exceptions.MySQLTransactionRollbackException: Lock wait timeout exceeded; try restarting transaction

posted on 2020-08-06 10:12  mindSucker  阅读(784)  评论(0编辑  收藏  举报