html5中文学习网

您的位置: 首页 > 网络编程 > java教程 » 正文

Mybatis update数据库死锁之获取数据库连接池等待_java_

[ ] 已经帮助:人解决问题

 最近学习测试mybatis,单个增删改查都没问题,最后使用mvn test的时候发现了几个问题:EsLHTML5中文学习网 - HTML5先行者学习网
EsLHTML5中文学习网 - HTML5先行者学习网

1.update失败,原因是数据库死锁EsLHTML5中文学习网 - HTML5先行者学习网
EsLHTML5中文学习网 - HTML5先行者学习网

2.select等待,原因是connection连接池被用光了,需要等待EsLHTML5中文学习网 - HTML5先行者学习网
EsLHTML5中文学习网 - HTML5先行者学习网

get:EsLHTML5中文学习网 - HTML5先行者学习网
EsLHTML5中文学习网 - HTML5先行者学习网

1.要勇于探索,坚持就是胜利。刚看到错误的时候直接懵逼,因为错误完全看不出来,属于框架内部报错,在犹豫是不是直接睡EsLHTML5中文学习网 - HTML5先行者学习网

觉得了,毕竟也快12点了。最后还是给我一点点找到问题所在了。EsLHTML5中文学习网 - HTML5先行者学习网

2.同上,要敢于去深入你不了解的代码,敢于研究不懂的代码。EsLHTML5中文学习网 - HTML5先行者学习网
EsLHTML5中文学习网 - HTML5先行者学习网

3.距离一个合格的码农越来越远了,因为越学越觉得漏洞百出,自己的代码到处都是坑。所以,一定要记录下来。EsLHTML5中文学习网 - HTML5先行者学习网
EsLHTML5中文学习网 - HTML5先行者学习网

下面记录这两个问题。EsLHTML5中文学习网 - HTML5先行者学习网
EsLHTML5中文学习网 - HTML5先行者学习网

1.mysql数据库死锁EsLHTML5中文学习网 - HTML5先行者学习网
EsLHTML5中文学习网 - HTML5先行者学习网

这里,感谢http://www.cnblogs.com/lin-xuan/p/5280614.html,我找到了答案。在这里,我还是重现一下:EsLHTML5中文学习网 - HTML5先行者学习网
EsLHTML5中文学习网 - HTML5先行者学习网

数据库死锁是事务性数据库 (如SQL Server, MySql等)经常遇到的问题。除非数据库死锁问题频繁出现导致用户无法操作,一般情况下数据库死锁问题不严重。在应用程序中进行try-catch就可以。那么数据死锁是如何产生的呢?EsLHTML5中文学习网 - HTML5先行者学习网
EsLHTML5中文学习网 - HTML5先行者学习网

InnoDB实现的是行锁 (row level lock),分为共享锁 (S) 和 互斥锁 (X)。EsLHTML5中文学习网 - HTML5先行者学习网
EsLHTML5中文学习网 - HTML5先行者学习网

•共享锁用于事务read一行。EsLHTML5中文学习网 - HTML5先行者学习网
•互斥锁用于事务update或delete一行。EsLHTML5中文学习网 - HTML5先行者学习网
EsLHTML5中文学习网 - HTML5先行者学习网

当客户A持有共享锁S,并请求互斥锁X;同时客户B持有互斥锁X,并请求共享锁S。以上情况,会发生数据库死锁。如果还不够清楚,请看下面的例子。EsLHTML5中文学习网 - HTML5先行者学习网
EsLHTML5中文学习网 - HTML5先行者学习网

双开两个mysql客户端EsLHTML5中文学习网 - HTML5先行者学习网
EsLHTML5中文学习网 - HTML5先行者学习网

客户端A:EsLHTML5中文学习网 - HTML5先行者学习网
EsLHTML5中文学习网 - HTML5先行者学习网

开启事务,并锁定共享锁S 在id=12的时候:EsLHTML5中文学习网 - HTML5先行者学习网

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:EsLHTML5中文学习网 - HTML5先行者学习网
EsLHTML5中文学习网 - HTML5先行者学习网

开启事务,尝试删除id=12:EsLHTML5中文学习网 - HTML5先行者学习网
EsLHTML5中文学习网 - HTML5先行者学习网

mysql> START TRANSACTION;Query OK, 0 rows affected (0.00 sec)mysql> DELETE FROM blog WHERE id = 12;

删除操作需要互斥锁 (X),但是互斥锁X和共享锁S是不能相容的。所以删除事务被放到锁请求队列中,客户B阻塞。EsLHTML5中文学习网 - HTML5先行者学习网
EsLHTML5中文学习网 - HTML5先行者学习网

这时候客户端A也想要删除12:EsLHTML5中文学习网 - HTML5先行者学习网

mysql> DELETE FROM blog WHERE id = 12;Query OK, 1 row affected (0.00 sec)

和参考文章不同的是,居然删除成功了,但客户端B出错了:EsLHTML5中文学习网 - HTML5先行者学习网
EsLHTML5中文学习网 - HTML5先行者学习网

ERROR 1213 (40001): Deadlock found when trying to get lock; try restarting transaction EsLHTML5中文学习网 - HTML5先行者学习网
EsLHTML5中文学习网 - HTML5先行者学习网

于是,我尝试删除13,这下都阻塞了:EsLHTML5中文学习网 - HTML5先行者学习网
EsLHTML5中文学习网 - HTML5先行者学习网

EsLHTML5中文学习网 - HTML5先行者学习网

我的mybatis测试代码中,因为上一个测试没有commit导致死锁,commit后就ok了。在这里,我想说,数据库的东西全还给老师了,关于锁以及事务需要重新温习一下了。EsLHTML5中文学习网 - HTML5先行者学习网
EsLHTML5中文学习网 - HTML5先行者学习网

2.Mybatis中datasource的数据库连接数EsLHTML5中文学习网 - HTML5先行者学习网
EsLHTML5中文学习网 - HTML5先行者学习网

当我mvn test的时候,我发现有个查询的test打印日志:EsLHTML5中文学习网 - HTML5先行者学习网
EsLHTML5中文学习网 - HTML5先行者学习网

2016-07-21 23:43:53,356 DEBUG [org.apache.ibatis.transaction.jdbc.JdbcTransaction] - Opening JDBC ConnectionEsLHTML5中文学习网 - HTML5先行者学习网
2016-07-21 23:43:53,356 DEBUG [org.apache.ibatis.datasource.pooled.PooledDataSource] - Waiting as long as 20000 milliseconds for connection.EsLHTML5中文学习网 - HTML5先行者学习网

于是,果然等了一段时间后才执行成功。跟踪源码,找到这处日志就明白了。首先,我这里使用的数据库连接配置是mybatis默认的:EsLHTML5中文学习网 - HTML5先行者学习网
EsLHTML5中文学习网 - HTML5先行者学习网

<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个就会等待,不然就报错。EsLHTML5中文学习网 - HTML5先行者学习网

以上所述是小编给大家介绍的Mybatis update数据库死锁之获取数据库连接池等待,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对脚本之家网站的支持!EsLHTML5中文学习网 - HTML5先行者学习网

(责任编辑:)
推荐书籍
推荐资讯
关于HTML5先行者 - 联系我们 - 广告服务 - 友情链接 - 网站地图 - 版权声明 - 人才招聘 - 帮助