Mybatis update數據庫逝世鎖之獲得數據庫銜接池期待。本站提示廣大學習愛好者:(Mybatis update數據庫逝世鎖之獲得數據庫銜接池期待)文章只能為提供參考,不一定能成為您想要的結果。以下是Mybatis update數據庫逝世鎖之獲得數據庫銜接池期待正文
比來進修測試mybatis,單個增刪改查都沒成績,最初應用mvn test的時刻發明了幾個成績:
1.update掉敗,緣由是數據庫逝世鎖
2.select期待,緣由是connection銜接池被用光了,須要期待
get:
1.要勇於摸索,保持就是成功。剛看到毛病的時刻直接懵逼,由於毛病完整看不出來,屬於框架外部報錯,在遲疑是否是直接睡
認為了,究竟也快12點了。最初照樣給我一點點找到成績地點了。
2.同上,要勇於去深刻你不懂得的代碼,勇於研討不懂的代碼。
3.間隔一個及格的碼農愈來愈遠了,由於越學越認為破綻百出,本身的代碼隨處都是坑。所以,必定要記載上去。
上面記載這兩個成績。
1.mysql數據庫逝世鎖
這裡,感激http://www.cnblogs.com/lin-xuan/p/5280614.html,我找到了謎底。在這裡,我照樣重現一下:
數據庫逝世鎖是事務性數據庫 (如SQL Server, MySql等)常常碰到的成績。除非數據庫逝世鎖成績頻仍湧現招致用戶沒法操作,普通情形下數據庫逝世鎖成績不嚴重。在運用法式中停止try-catch便可以。那末數據逝世鎖是若何發生的呢?
InnoDB完成的是行鎖 (row level lock),分為同享鎖 (S) 和 互斥鎖 (X)。
•同享鎖用於事務read一行。
•互斥鎖用於事務update或delete一行。
當客戶A持有同享鎖S,並要求互斥鎖X;同時客戶B持有互斥鎖X,並要求同享鎖S。以下情況,會產生數據庫逝世鎖。假如還不敷清晰,請看上面的例子。
雙開兩個mysql客戶端
客戶端A:
開啟事務,並鎖定同享鎖S 在id=12的時刻:
mysql> START TRANSACTION; Query OK, 0 rows affected (0.00 sec) mysql> SELECT * FROM blog WHERE id = 12 LOCK IN SHARE MODE; +----+-------+-----------+ | id | name | author_id | +----+-------+-----------+ | 12 | testA | 50 | +----+-------+-----------+ 1 row in set (0.00 sec)
客戶端B:
開啟事務,測驗考試刪除id=12:
mysql> START TRANSACTION; Query OK, 0 rows affected (0.00 sec) mysql> DELETE FROM blog WHERE id = 12;
刪除操作須要互斥鎖 (X),然則互斥鎖X和同享鎖S是不克不及相容的。所以刪除事務被放到鎖要求隊列中,客戶B壅塞。
這時候候客戶端A也想要刪除12:
mysql> DELETE FROM blog WHERE id = 12; Query OK, 1 row affected (0.00 sec)
和參考文章分歧的是,竟然刪除勝利了,但客戶端B失足了:
ERROR 1213 (40001): Deadlock found when trying to get lock; try restarting transaction
因而,我測驗考試刪除13,這下都壅塞了:
我的mybatis測試代碼中,由於上一個測試沒有commit招致逝世鎖,commit後就ok了。在這裡,我想說,數據庫的器械全還給先生了,關於鎖和事務須要從新復習一下了。
2.Mybatis中datasource的數據庫銜接數
當我mvn test的時刻,我發明有個查詢的test打印日記:
2016-07-21 23:43:53,356 DEBUG [org.apache.ibatis.transaction.jdbc.JdbcTransaction] - Opening JDBC Connection
2016-07-21 23:43:53,356 DEBUG [org.apache.ibatis.datasource.pooled.PooledDataSource] - Waiting as long as 20000 milliseconds for connection.
因而,果真等了一段時光後才履行勝利。跟蹤源碼,找到這處日記就明確了。起首,我這裡應用的數據庫銜接設置裝備擺設是mybatis默許的:
<environment id="development"> <transactionManager type="JDBC"/> <dataSource type="POOLED"> <property name="driver" value="${jdbc.driver}"/> <property name="url" value="${jdbc.url}"/> <property name="username" value="${jdbc.username}"/> <property name="password" value="${jdbc.password}"/> </dataSource> </environment> 當數據庫銜接池的銜接數用光了以後就要等2s再去獲得: while (conn == null) { synchronized (state) { if (!state.idleConnections.isEmpty()) { // Pool has available connection conn = state.idleConnections.remove(0); if (log.isDebugEnabled()) { log.debug("Checked out connection " + conn.getRealHashCode() + " from pool."); } } else { // Pool does not have available connection if (state.activeConnections.size() < poolMaximumActiveConnections) { // Can create new connection conn = new PooledConnection(dataSource.getConnection(), this); if (log.isDebugEnabled()) { log.debug("Created connection " + conn.getRealHashCode() + "."); } } else { // Cannot create new connection PooledConnection oldestActiveConnection = state.activeConnections.get(0); long longestCheckoutTime = oldestActiveConnection.getCheckoutTime(); if (longestCheckoutTime > poolMaximumCheckoutTime) { // Can claim overdue connection state.claimedOverdueConnectionCount++; state.accumulatedCheckoutTimeOfOverdueConnections += longestCheckoutTime; state.accumulatedCheckoutTime += longestCheckoutTime; state.activeConnections.remove(oldestActiveConnection); if (!oldestActiveConnection.getRealConnection().getAutoCommit()) { try { oldestActiveConnection.getRealConnection().rollback(); } catch (SQLException e) { log.debug("Bad connection. Could not roll back"); } } conn = new PooledConnection(oldestActiveConnection.getRealConnection(), this); oldestActiveConnection.invalidate(); if (log.isDebugEnabled()) { log.debug("Claimed overdue connection " + conn.getRealHashCode() + "."); } } else { // Must wait try { if (!countedWait) { state.hadToWaitCount++; countedWait = true; } if (log.isDebugEnabled()) { log.debug("Waiting as long as " + poolTimeToWait + " milliseconds for connection."); } long wt = System.currentTimeMillis(); state.wait(poolTimeToWait); state.accumulatedWaitTime += System.currentTimeMillis() - wt; } catch (InterruptedException e) { break; } } } } if (conn != null) { if (conn.isValid()) { if (!conn.getRealConnection().getAutoCommit()) { conn.getRealConnection().rollback(); } conn.setConnectionTypeCode(assembleConnectionTypeCode(dataSource.getUrl(), username, password)); conn.setCheckoutTimestamp(System.currentTimeMillis()); conn.setLastUsedTimestamp(System.currentTimeMillis()); state.activeConnections.add(conn); state.requestCount++; state.accumulatedRequestTime += System.currentTimeMillis() - t; } else { if (log.isDebugEnabled()) { log.debug("A bad connection (" + conn.getRealHashCode() + ") was returned from the pool, getting another connection."); } state.badConnectionCount++; localBadConnectionCount++; conn = null; if (localBadConnectionCount > (poolMaximumIdleConnections + 3)) { if (log.isDebugEnabled()) { log.debug("PooledDataSource: Could not get a good connection to the database."); } throw new SQLException("PooledDataSource: Could not get a good connection to the database."); } } } } }
當銜接數少於10個的時刻回創立,跨越10個就會期待,否則就報錯。
以上所述是小編給年夜家引見的Mybatis update數據庫逝世鎖之獲得數據庫銜接池期待,願望對年夜家有所贊助,假如年夜家有任何疑問請給我留言,小編會實時答復年夜家的。在此也異常感激年夜家對網站的支撐!