国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 編程 > Java > 正文

Mybatis update數據庫死鎖之獲取數據庫連接池等待

2019-11-26 14:02:33
字體:
來源:轉載
供稿:網友

 最近學習測試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 connectionconn = state.idleConnections.remove(0);if (log.isDebugEnabled()) {log.debug("Checked out connection " + conn.getRealHashCode() + " from pool.");}} else {// Pool does not have available connectionif (state.activeConnections.size() < poolMaximumActiveConnections) {// Can create new connectionconn = new PooledConnection(dataSource.getConnection(), this);if (log.isDebugEnabled()) {log.debug("Created connection " + conn.getRealHashCode() + ".");}} else {// Cannot create new connectionPooledConnection oldestActiveConnection = state.activeConnections.get(0);long longestCheckoutTime = oldestActiveConnection.getCheckoutTime();if (longestCheckoutTime > poolMaximumCheckoutTime) {// Can claim overdue connectionstate.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 waittry {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數據庫死鎖之獲取數據庫連接池等待,希望對大家有所幫助,如果大家有任何疑問請給我留言,小編會及時回復大家的。在此也非常感謝大家對武林網網站的支持!

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 扎囊县| 兴义市| 常宁市| 峨眉山市| 和林格尔县| 鹤壁市| 东丰县| 黑河市| 宜川县| 卓尼县| 新宾| 张掖市| 日照市| 邵阳市| 商城县| 高台县| 巴东县| 广灵县| 溧阳市| 板桥市| 临海市| 靖宇县| 米林县| 安多县| 台前县| 兴仁县| 龙山县| 南木林县| 桐梓县| 岗巴县| 都昌县| 江达县| 会同县| 乐业县| 锦屏县| 明光市| 克拉玛依市| 安远县| 永靖县| 玉环县| 大田县|