最近項目中頻繁出現 Lock wait timeout exceeded; try restarting transaction這個錯誤,把我們弄得痛苦不堪啊,為了解決問題,上網上找好多資料,終於把問題復現了。具體操作步驟如下(我使用的mysql工具是 navicat):
第一步:開啟sql命令頁面
第二步:輸入start transaction;開啟一個事務
第三步:輸入update語句 UPDATE TABLENAME set time=null where id=29163;(切記不要 提交(commit;))
第四步:書寫測試類
public class StTest implements Runnable{ private static ApplicationContext applicationContext=null; private static AtomicInteger a=new AtomicInteger(0); static { applicationContext=new ClassPathXmlApplicationContext("classpath:application.xml"); } public static void main(String[] args) throws Exception { ExecutorService executorService = Executors.newFixedThreadPool(10); for (int i = 0; i <10 ; i++) { executorService.execute(new aaaa()); } if(!executorService.isTerminated()){ executorService.shutdown(); } } @Override public void run() { XXXService bean = applicationContext.getBean(XXXService.class); XXXBeand xx= null; try { xx= bean.byId(254213); } catch (Exception e) { e.printStackTrace(); } long aaa=System.currentTimeMillis(); for (int i = 0; i < 10; i++) { try { bean.update(xx); } catch (Exception e) { e.printStackTrace(); } } System.out.println(System.currentTimeMillis()-aaa); } }
運行程序並且運行下面3個sql查看結果
SELECT * FROM information_schema.INNODB_TRX; select * from information_schema.innodb_lock_waits; select * from information_schema.innodb_locks;
得到以下運行結果。我們發現有其他幾個的 trx_state 狀態是LOCK WAIT,得到我們要復現的結果
第五步:等待錯誤出現,在我們等待一段時間之后會發現程序報錯
Caused by: java.sql.SQLException: Lock wait timeout exceeded; try restarting transaction at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:1055) at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:956) at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:3491) at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:3423) at com.mysql.jdbc.MysqlIO.sendCommand(MysqlIO.java:1936) at com.mysql.jdbc.MysqlIO.sqlQueryDirect(MysqlIO.java:2060) at com.mysql.jdbc.ConnectionImpl.execSQL(ConnectionImpl.java:2542) at com.mysql.jdbc.PreparedStatement.executeInternal(PreparedStatement.java:1734) at com.mysql.jdbc.PreparedStatement.execute(PreparedStatement.java:995) at com.alibaba.druid.pool.DruidPooledPreparedStatement.execute(DruidPooledPreparedStatement.java:493) at sun.reflect.GeneratedMethodAccessor21.invoke(Unknown Source) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:606) at org.apache.ibatis.logging.jdbc.PreparedStatementLogger.invoke(PreparedStatementLogger.java:55) at com.sun.proxy.$Proxy17.execute(Unknown Source) at org.apache.ibatis.executor.statement.PreparedStatementHandler.update(PreparedStatementHandler.java:41) at org.apache.ibatis.executor.statement.RoutingStatementHandler.update(RoutingStatementHandler.java:66) at org.apache.ibatis.executor.SimpleExecutor.doUpdate(SimpleExecutor.java:45) at org.apache.ibatis.executor.BaseExecutor.update(BaseExecutor.java:100) at org.apache.ibatis.executor.CachingExecutor.update(CachingExecutor.java:75) at sun.reflect.GeneratedMethodAccessor35.invoke(Unknown Source) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:606) at org.apache.ibatis.plugin.Plugin.invoke(Plugin.java:59) at com.sun.proxy.$Proxy15.update(Unknown Source) at org.apache.ibatis.session.defaults.DefaultSqlSession.update(DefaultSqlSession.java:148) at sun.reflect.GeneratedMethodAccessor34.invoke(Unknown Source) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:606) at org.mybatis.spring.SqlSessionTemplate$SqlSessionInterceptor.invoke(SqlSessionTemplate.java:354) ... 20 more
從上面得到的結果,可以知道這個錯誤是在一個事務沒有提交的時候,其他事務也操作相同對象導致的,那么找到了問題的原因,我們就可以針對這種情況進行修改了。
這是本次我遇到的錯誤,分享給大家一下,以避免程序中遇到這樣的情況。