MySQLTransactionRollbackException: Lock wait timeout exceeded; try restarting transaction

解决思路

  1. 找到一直未提交的事务
  2. 把这个事务杀掉

解决方案细节

  1. 查找未提交的事务
mysql> select trx_id,trx_state from information_schema.innodb_trx;
+--------+-----------+
| trx_id | trx_state |
+--------+-----------+
| 101927 | RUNNING   |
+--------+-----------+
1 row in set (0.00 sec)

可以看到有一个事务没有提交,id为101927

  1. 查找未提交事务的 session
mysql> show full processlist;
+----+-----------------+-----------------+--------+---------+--------+------------------------+-----------------------+
| Id | User            | Host            | db     | Command | Time   | State                  | Info                  |
+----+-----------------+-----------------+--------+---------+--------+------------------------+-----------------------+
|  5 | event_scheduler | localhost       | NULL   | Daemon  | 376984 | Waiting on empty queue | NULL                  |
|  9 | root            | localhost:12255 | db_seq | Sleep   |     53 |                        | NULL                  |
| 11 | root            | localhost:12733 | db_seq | Query   |      0 | init                   | show full processlist |
| 12 | root            | localhost:12764 | db_seq | Sleep   |     19 |                        | NULL                  |
| 13 | root            | localhost:12790 | NULL   | Sleep   |     27 |                        | NULL                  |
+----+-----------------+-----------------+--------+---------+--------+------------------------+-----------------------+

这里没有复现出来,如果一个事务卡很久它的 Command 会是 Query,假装这里12号session是卡着没提交的会话;

  1. 杀死会话
mysql> kill 12;
Query OK, 0 rows affected (0.00 sec)

执行完在程序那边会抛个异常,表示事务提交失败,数据进行了回滚。
这样就不会卡着其他事务提交了

问题背景介绍

我同事上线了一个新的服务, 然后我又把数据库的字段改了, 阴差阳错导致了锁表, 事务又未提交, 新服务在疯狂抛异常

详细报错

2019-07-08 10:03:01.048 [SimpleAsyncTaskExecutor-1] INFO  o.s.beans.factory.xml.XmlBeanDefinitionReader - Loading XML bean definitions from class path resource [org/springframework/jdbc/support/sql-error-codes.xml]
2019-07-08 10:03:01.085 [SimpleAsyncTaskExecutor-1] ERROR o.s.a.i.SimpleAsyncUncaughtExceptionHandler - Unexpected error occurred invoking async method: public void com.kingseok.security.domain.AuthDomain.incrementLoginCount(com.kingseok.security.entity.User,com.kingseok.security.constant.OpenApiLoginSourceEnum)
org.springframework.dao.CannotAcquireLockException: 
### Error updating database.  Cause: com.mysql.cj.jdbc.exceptions.MySQLTransactionRollbackException: Lock wait timeout exceeded; try restarting transaction
### The error may involve com.kingseok.security.mapper.UserMapper.updateByPrimaryKeySelective-Inline
### The error occurred while setting parameters
### SQL: update user_      SET login_count = ?,                       last_login_time = ?,                                                                 online_status = ?,                       login_source = ?      where id = ?
### Cause: com.mysql.cj.jdbc.exceptions.MySQLTransactionRollbackException: Lock wait timeout exceeded; try restarting transaction
; ]; Lock wait timeout exceeded; try restarting transaction; nested exception is com.mysql.cj.jdbc.exceptions.MySQLTransactionRollbackException: Lock wait timeout exceeded; try restarting transaction
	at org.springframework.jdbc.support.SQLErrorCodeSQLExceptionTranslator.doTranslate(SQLErrorCodeSQLExceptionTranslator.java:262)
	at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:72)
	at org.mybatis.spring.MyBatisExceptionTranslator.translateExceptionIfPossible(MyBatisExceptionTranslator.java:73)
	at org.mybatis.spring.SqlSessionTemplate$SqlSessionInterceptor.invoke(SqlSessionTemplate.java:446)
	at com.sun.proxy.$Proxy88.update(Unknown Source)
	at org.mybatis.spring.SqlSessionTemplate.update(SqlSessionTemplate.java:294)
	at org.apache.ibatis.binding.MapperMethod.execute(MapperMethod.java:63)
	at org.apache.ibatis.binding.MapperProxy.invoke(MapperProxy.java:59)
	at com.sun.proxy.$Proxy89.updateByPrimaryKeySelective(Unknown Source)
	at com.kingseok.security.domain.UserDomain.update(UserDomain.java:51)
	at com.kingseok.security.domain.AuthDomain.incrementLoginCount(AuthDomain.java:74)
	at com.kingseok.security.domain.AuthDomain$$FastClassBySpringCGLIB$$6a656ac4.invoke(<generated>)
	at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204)
	at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:746)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163)
	at org.springframework.aop.interceptor.AsyncExecutionInterceptor.lambda$invoke$0(AsyncExecutionInterceptor.java:115)
	at java.util.concurrent.FutureTask.run$$$capture(FutureTask.java:266)
	at java.util.concurrent.FutureTask.run(FutureTask.java)
	at java.lang.Thread.run(Thread.java:748)
Caused by: com.mysql.cj.jdbc.exceptions.MySQLTransactionRollbackException: Lock wait timeout exceeded; try restarting transaction
	at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:123)
	at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:97)
	at com.mysql.cj.jdbc.exceptions.SQLExceptionsMapping.translateException(SQLExceptionsMapping.java:122)
	at com.mysql.cj.jdbc.ClientPreparedStatement.executeInternal(ClientPreparedStatement.java:974)
	at com.mysql.cj.jdbc.ClientPreparedStatement.execute(ClientPreparedStatement.java:391)
	at com.zaxxer.hikari.pool.ProxyPreparedStatement.execute(ProxyPreparedStatement.java:44)
	at com.zaxxer.hikari.pool.HikariProxyPreparedStatement.execute(HikariProxyPreparedStatement.java)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at org.apache.ibatis.logging.jdbc.PreparedStatementLogger.invoke(PreparedStatementLogger.java:59)
	at com.sun.proxy.$Proxy130.execute(Unknown Source)
	at org.apache.ibatis.executor.statement.PreparedStatementHandler.update(PreparedStatementHandler.java:46)
	at org.apache.ibatis.executor.statement.RoutingStatementHandler.update(RoutingStatementHandler.java:74)
	at org.apache.ibatis.executor.SimpleExecutor.doUpdate(SimpleExecutor.java:50)
	at org.apache.ibatis.executor.BaseExecutor.update(BaseExecutor.java:117)
	at org.apache.ibatis.executor.CachingExecutor.update(CachingExecutor.java:76)
	at org.apache.ibatis.session.defaults.DefaultSqlSession.update(DefaultSqlSession.java:198)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at org.mybatis.spring.SqlSessionTemplate$SqlSessionInterceptor.invoke(SqlSessionTemplate.java:433)
	... 15 common frames omitted
2019-07-08 10:11:20.666 [http-nio-7070-exec-4] ERROR c.kingseok.security.controller.ExceptionController - nested exception is org.apache.ibatis.exceptions.PersistenceException: 
### Error querying database.  Cause: org.springframework.jdbc.CannotGetJdbcConnectionException: Failed to obtain JDBC Connection; nested exception is java.sql.SQLTransientConnectionException: HikariPool-1 - Connection is not available, request timed out after 30009ms.
### The error may exist in com/kingseok/security/mapper/UserMapper.xml
### The error may involve com.kingseok.security.mapper.UserMapper.selectByExample
### The error occurred while executing a query
### Cause: org.springframework.jdbc.CannotGetJdbcConnectionException: Failed to obtain JDBC Connection; nested exception is java.sql.SQLTransientConnectionException: HikariPool-1 - Connection is not available, request timed out after 30009ms.

参考链接

MySQLTransactionRollbackException: Lock wait timeout exceeded; try restarting transactionMySQL数据库中的一种常见错误,它通常发生在尝试获取锁但等待时间超过系统设置的阈值时。这可能是因为并发操作太多,导致资源争夺,或者事务处理过程中出现了阻塞。 解决这个问题的步骤可以包括: 1. **检查并发量**:确认是否有过多的并发连接在运行,尝试减少并发数或优化查询性能。 2. **增加锁超时时间**:在MySQL配置中,可以通过`innodb_lock_wait_timeout`参数调整锁等待超时时间,但要注意,太大的值可能会导致性能下降。 3. **优化SQL查询**:确保查询是有效的,并使用索引来提高数据访问速度。避免使用SELECT *,只选择真正需要的列。 4. **使用RESTART TRANSACTION**:在Java代码中,如果你知道当前事务存在问题并可以重试,可以尝试使用`connection.rollback()`然后`connection.commit()`来重启事务,但务必谨慎,因为这可能导致数据不一致。 5. **检查死锁**:使用`SHOW ENGINE INNODB STATUS`命令检查是否发生了死锁,如果是,则需要手动解决死锁或优化事务处理策略。 6. **监控数据库状态**:定期检查MySQL服务器的日志文件,查看是否有其他异常信息可以帮助诊断问题。 如果你正在使用JDBC进行编程,你可以在遇到这个异常时捕获并处理,例如添加重试逻辑或者记录日志以追踪问题。
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值