ERROR [com.alibaba.druid.pool.DruidDataSource] - 接続を放棄してください。
概要
この記事では、Druidの接続漏れの問題を解決する方法を説明します、プロセスが少し複雑なので、私は詳細に手順とアイデアを記録します、それがあなたの助けとインスピレーションがあれば、コメントを残してください
#プロジェクト構成
MyBatis+TDDL
質問
https://github.com/FS1360472174/javaweb/issues/58
ERROR [com.alibaba.druid.pool.DruidDataSource] - 接続を放棄、所有者スレッド: qtp1267032364
-14 で接続されました。1515409987672 で接続、スタックトレースを開く
at java.lang.Thread.getStackTrace(Thread.java:1556)
com.alibaba.druid.pool.DruidDataSource.getConnectionDirect(DruidDataSource.java:1068)にて。
at com.alibaba.druid.pool.DruidDataSource.getConnection(DruidDataSource.java:994)
at com.alibaba.druid.pool.DruidDataSource.getConnection(DruidDataSource.java:984)
at com.taobao.tddl.atom.jdbc.TDataSourceWrapper.getConnectionByTargetDataSource(TDataSourceWrapper.java:322)
at com.taobao.tddl.atom.jdbc.TDataSourceWrapper.getConnection0(TDataSourceWrapper.java:284)
at com.taobao.tddl.atom.jdbc.TDataSourceWrapper.getConnection(TDataSourceWrapper.java:255)
at com.taobao.tddl.atom.jdbc.TDataSourceWrapper.getConnection(TDataSourceWrapper.java:222)
at com.taobao.tddl.atom.AbstractTAtomDataSource.getConnection(AbstractTAtomDataSource.java:27)
at com.taobao.tddl.group.jdbc.DataSourceWrapper.getConnection(DataSourceWrapper.java:120)
at com.taobao.tddl.group.jdbc.TGroupConnection.createNewConnection(TGroupConnection.java:191)
at com.taobao.tddl.group.jdbc.TGroupConnection$1.tryOnDataSource(TGroupConnection.java:453)
at com.taobao.tddl.group.jdbc.TGroupConnection$1.tryOnDataSource(TGroupConnection.java:443)
at com.taobao.tddl.group.dbselector.AbstractDBSelector.tryOnDataSourceHolderWithIndex(AbstractDBSelector.java:19)
at com.taobao.tddl.group.dbselector.AbstractDBSelector.tryExecute(AbstractDBSelector.java:315)
at com.taobao.tddl.group.jdbc.TGroupConnection.prepareCall(TGroupConnection.java:492)
at com.tao.tddl.group.jdbc.TGroupConnection.prepareCall(TGroupConnection.java:520)
at com.tao.tddl.group.jdbc.TGroupConnection.prepareCall(TGroupConnection.java:74)
at com.taobao.tddl.matrix.jdbc.TConnection.prepareCall(TConnection.java:515)
at com.taobao.tddl.matrix.jdbc.TConnection.prepareCall(TConnection.java:483)
14980,1-8 99%
at com.taobao.tddl.group.jdbc.TGroupConnection.prepareCall(TGroupConnection.java:74)
at com.taobao.tddl.matrix.jdbc.TConnection.prepareCall(TConnection.java:515)
at com.taobao.tddl.matrix.jdbc.TConnection.prepareCall(TConnection.java:483)
オンラインで他の問題をトラブルシューティングしているとき、ログにこのERRORが表示され、非常に頻繁に表示されます。
abandon connectionによると、これはデータベース接続プールの問題であり、非推奨の接続で処理されていることがわかります。
解決手順
-
まずドルイド公式サイトのFAQを検索
https://github.com/alibaba/druid/wiki/常见问题
接続漏れの監視処理をしていたのはドルイドであることが判明https://github.com/alibaba/druid/wiki/连接泄漏监测
https://github.com/alibaba/druid/issues/872
私の方ではペアリング監視を行わず、ログから直接、対応するスレッドスタック情報を取得して、トラブルシューティングを簡単に行うことができます。public DruidPooledConnection getConnectionDirect(long maxWaitMillis) throws SQLException { int notFullTimeoutRetryCnt = 0; DruidPooledConnection poolableConnection; while(true) { while(true) { try { Connection realConnection = poolableConnection.getConnection(); this.discardConnection(realConnection); } else { Connection realConnection = poolableConnection.getConnection(); if(realConnection.isClosed()) { this.discardConnection((Connection)null); } else { if(!this.isTestWhileIdle()) { break; } long currentTimeMillis = System.currentTimeMillis(); long lastActiveTimeMillis = poolableConnection.getConnectionHolder().getLastActiveTimeMillis(); long idleMillis = currentTimeMillis - lastActiveTimeMillis; long timeBetweenEvictionRunsMillis = this.getTimeBetweenEvictionRunsMillis(); if(timeBetweenEvictionRunsMillis <= 0L) { timeBetweenEvictionRunsMillis = 60000L; } if(idleMillis < timeBetweenEvictionRunsMillis) { break; } this.discardConnection(realConnection); } } } if(this.isRemoveAbandoned()) { StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace(); poolableConnection.setConnectStackTrace(stackTrace); poolableConnection.setConnectedTimeNano(); poolableConnection.setTraceEnable(true); Map var21 = this.activeConnections; synchronized(this.activeConnections) { this.activeConnections.put(poolableConnection, PRESENT); } } if(!this.isDefaultAutoCommit()) { poolableConnection.setAutoCommit(false); } return poolableConnection; }
-
この接続リークはOOMを引き起こしません。なぜなら、druidは先に進んで、これらの閉じていない接続を積極的に破棄するからです。
-
これで、閉じられていないデータベース接続があることがわかりましたが、コードはデータベース接続プールを管理しておらず、Springに管理を任せており、すべてのデータベース操作に問題があるわけではなく、特定のデータベース操作に問題があることがわかります
-
デバッグログをオンにする
2018-01-23 21:08:35,760 DEBUG [org.springframework.data.redis.core.RedisConnectionUtils] - Opening RedisConnection
2018-01-23 21:08:35,761 DEBUG [org.springframework.data.redis.core.RedisConnectionUtils] - Closing Redis Connection
2018-01-23 21:08:35,762 DEBUG [org.mybatis.spring.SqlSessionUtils] - Creating a new SqlSession
2018-01-23 21:08:35,762 DEBUG [org.mybatis.spring.SqlSessionUtils] - SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@ 5ba28a19] was not registered for synchronization because synchronization is not active
2018-01-23 21:08:35,765 DEBUG [org.springframework.jdbc.datasource.DataSourceUtils] - Fetching JDBC Connection from DataSource
2018-01-23 21:08:35,765 DEBUG [org.mybatis.spring.transaction.SpringManagedTransaction] - JDBC Connection [com.taobao.tddl.matrix.jdbc. TConnection@24f6de0] will not be managed by Spring
2018-01-23 21:08:35,766 DEBUG [com.taobao.tddl.group.jdbc.TGroupConnection] - [TDDL] dataSourceIndex=GroupIndex [index=0, failRetry=false] , tddl version: 5.1.7
2018-01-23 21:08:35,810 DEBUG [org.mybatis.spring.SqlSessionUtils] - Closing non transactional SqlSession [org.apache.ibatis.session. defaults.DefaultSqlSession@5ba28a19]
2018-01-23 21:08:35,810 DEBUG [org.springframework.jdbc.datasource.DataSourceUtils] - Returning JDBC Connection to DataSource
このように、Aliのオープンソースソフトウェアは、まだ産業用にはほど遠いことがわかります。Springでは、接続の解放と復帰が明確にわかりますが、Druidではそうではありません。
-
これは特定のSQLに関連しているため、この特定のSQLの操作を見てください。
@Options(statementType = StatementType.CALLABLE) @Insert("<script> " + "</script>") int saveDemo(Demo demo);
これは以前誰かが残したものですが、この書き方は現在プロジェクトチームではあまり一般的ではなく、コードとSQL文の分離を実現できず、あまり推奨されていません。
ここのStatementTypeは、一般的にCallableStatementは、データベースのストアドプロシージャの操作のために、明らかにこのステートメントはそうではありませんストアドプロシージャを呼び出すよりも奇妙に見える、呼び出し可能です。前任者がなぜこのように書いたのかわからないので、まずこのStatementType.CALLABLEパラメータを消しました。 -
何かが間違っていたことが判明しました。呼び出しはエラーを報告しました。おかしなエラーで、auto generate id を使用せず、それを呼び出したのです。
これはMySQL 5.7ドライバのバグと思われるが、前任者はこの問題を回避するためにCallableStatementを使用して回避していた
You need to specify Statement.RETURN_GENERATED_KEYS to Statement.executeUpdate() or Connection. prepareStatement(). at com.taobao.tddl.repo.mysql.handler.PutMyHandlerCommon.handle(PutMyHandlerCommon.java:52) at com.taobao.tddl.executor.AbstractGroupExecutor.executeInner(AbstractGroupExecutor.java:59) at com.taobao.tddl.executor.AbstractGroupExecutor.execByExecPlanNode(AbstractGroupExecutor.java:40) at com.taobao.tddl.executor.TopologyExecutor.execByExecPlanNode(TopologyExecutor.java:59) at com.taobao.tddl.executor.MatrixExecutor.execByExecPlanNode(MatrixExecutor.java:282)
-
そこで、まず検証を xml に変更します。xml はデフォルトで PreparedStatement ですが、それでもエラーが発生するかどうかを確認します。
がなくなっていることがわかりました。 ということで、原因はCallableStatementによる
#explore-druid 接続管理
問題は解決したものの、druidがどのように接続を管理するのかがまだ分からないので、もう少し深く掘り下げてみる必要があります。
-
マイバティス
まず、プロジェクトではMybatisを使用しており、Mybatis + jdbcの操作の流れは以下のようになります。
データベース操作は、特定のSQLが実行されたときのみ接続を取得する -
Spring-jdbcの紹介
トランザクション管理用
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<tx:annotation-driven transaction-manager="transactionManager"/>
この時点で、コネクションプールの管理はSpringManagedTransactionに引き渡されます。
org.mybatis.spring.transaction.SpringManagedTransaction の略です。
private Statement prepareStatement(StatementHandler handler, Log statementLog) throws SQLException {
Connection connection = this.getConnection(statementLog);
Statement stmt = handler.prepare(connection, this.transaction.getTimeout());
handler.parameterize(stmt);
return stmt;
}
- TDDL
テーブルを分割し、コネクションプール管理をdruid自体に依存するため、TDDLを導入した
コネクションを取得する
実行時のTPreparedStatment。
リパッケージされたSQL、PreparedStatment
AutoCommitTransaction は接続を管理します。
getConnection,今回はConnection
取得はTGroupConnectionのcreateNewConnectionです。
接続を閉じる
SqlSessionUtils.closeSqlSession
TConnection.close()を実行します。
TConnectionWrapper.close()
DruidPooledConnection.close()を実行します。
DruidPooledConnection.syncClose()を実行します。
DruidPooledConnection.recycle() // このメソッドは、実際にドルイド接続を閉じます。
public DruidPooledConnection getConnectionDirect(long maxWaitMillis) throws SQLException {
int notFullTimeoutRetryCnt = 0;
DruidPooledConnection poolableConnection;
...
if(this.isRemoveAbandoned()) {
StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
poolableConnection.setConnectStackTrace(stackTrace);
poolableConnection.setConnectedTimeNano();
poolableConnection.setTraceEnable(true);
Map var21 = this.activeConnections;
synchronized(this.activeConnections) {
// put an active connection
this.activeConnections.put(poolableConnection, PRESENT);
}
}
if(!this.isDefaultAutoCommit()) {
poolableConnection.setAutoCommit(false);
}
return poolableConnection;
}
放棄を取り除く
public int removeAbandoned() {
int removeCount = 0;
long currrentNanos = System.nanoTime();
List<DruidPooledConnection> abandonedList = new ArrayList();
// The class variable activeConnections stores the connections that are not closed
Map var5 = this.activeConnections;
synchronized(this.activeConnections) {
// Get the value of this side
Iterator iter = this.activeConnections.keySet().iterator();
while(iter.hasNext()) {
DruidPooledConnection pooledConnection = (DruidPooledConnection)iter.next();
if(!pooledConnection.isRunning()) {
long timeMillis = (currrentNanos - pooledConnection.getConnectedTimeNano()) / 1000000L;
if(timeMillis >= this.removeAbandonedTimeoutMillis) {
iter.remove();
pooledConnection.setTraceEnable(false);
abandonedList.add(pooledConnection);
}
}
}
}
if(abandonedList.size() > 0) {
Iterator var14 = abandonedList.iterator();
while(true) {
DruidPooledConnection pooledConnection;
do {
while(true) {
if(!var14.hasNext()) {
return removeCount;
}
pooledConnection = (DruidPooledConnection)var14.next();
synchronized(pooledConnection) {
if(!pooledConnection.isDisable()) {
break;
}
}
}
JdbcUtils.close(pooledConnection);
pooledConnection.abandond();
++this.removeAbandonedCount;
++removeCount;
} while(!this.isLogAbandoned());
StringBuilder buf = new StringBuilder();
buf.append("abandon connection, owner thread: ");
LOG.error(buf.toString());
}
} else {
return removeCount;
}
}
修正されたSQL操作は閉じられていますが、CallableStatementは閉じられていないため、閉じられていない接続が存在することがわかります。
Javaインターネット技術交換グループ392669336に参加することを歓迎し、Javaの問題のすべての種類を交換するために大修道院長
修道院長】をフォローすると、記事の更新をいち早く受け取り、修道院長と共に技術修行の道を歩み始めることができます
#ref
http://blog.csdn.net/luanlouis/article/details/40422941
http://blog.csdn.net/luanlouis/article/details/37671851
関連
-
スタイルが読み込まれず、ブラウザコンソールでエラーが報告される。リソースはスタイルシートとして解釈されますが、MIMEタイプtext/htmlで転送されます。
-
myeclipseでコンパイルするとAntエラーが発生する javaの例外が発生しました。
-
プロジェクトの依存関係を解決できなかった 解決
-
スレッド "main" で例外発生 java.lang.ArrayIndexOutOfBoundsException: 0 at One1.main(One1.java:3)
-
Javaエラーメッセージがenclosingクラスでない
-
javaでよく使われる英単語
-
Eclipse起動エラー:javaは起動したが、終了コード=1を返した(ネット上の様々な落とし穴)
-
Javaドッキングリーダの落とし穴について終了コード -1073740940 (0xC0000374)でプロセス終了
-
javaで "Unhandled exception type ...... "を処理するには?
-
比較方式がその一般契約に違反している。
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
IllegalArgumentException この例外を解決する方法
-
Eclipseで "XXXX "の解決策を(型に)解決することができない
-
java Mail send email smtp is not authenticated by TLS encryption solution.
-
スレッド "main" での例外 java.lang.ArrayIndexOutOfBoundsException: 1
-
アイデア Springboot Web プロジェクトを jar にパッケージ化する場合、Error: 無効または破損した jarfile x.jar 解決策
-
[オリジナル】java学習ノート【II】よくあるエラー クラスパス上のクラスファイルが見つからない、またはアクセスできない場合
-
SocketTimeoutExceptionです。読み込みがタイムアウトしました
-
java.security.InvalidAlgorithmParameterException: TrustAnchors パラメータは空であってはなりません 解決策
-
SyntaxError: JSON入力の予期せぬ終了 解決策とアイデア
-
同期・並行クラスコンテナ