Spring Boot統合Druidに異常エラーが発生した原因と解決
Spring Boot統合Druid異常
Spring Boot統合Druidプロジェクトにおいて、エラーログには以下のようなエラーメッセージが頻繁に表示されていることが分かりました。
異常分析
まず上の異常はプログラムの正常な運行に影響しませんが、プログラマーとしてはプログラムに異常があることを見て耐えられません。だから、根掘り葉掘り聞いて解決します。
スタック情報を追跡すると、対応の異常がcomp.alibababa.druid.pool.DruidAbstract Data Source咻testConnection Internalメソッドから投げられたもので、対応するコードは以下の通りです。
原理追跡
上記のコードの中で、私達はこの業務のロジックに入るのが前提条件があるので、つまりvalidとisMySql変数は同時にtrueです。isMySqlはtrueのために必要です。私たちが使っているのはMysqlデータベースです。では、validをfalseにしてもいいですか?このようにすれば、この業務に入ることができなくなりますか?
validのソースを見に来ましたか?それともこの方法の上ですか?
pingに入る業務ロジックは主に変数usePingMethodによって判断されます。追跡コードはここで行われている設定を発見します。
Ping Methodを無効にします
問題の根源を見つけたら、残りはどうやって無効にしますか?
第一に、プログラムを起動する時に運転パラメータの中で増加します。-Ddruid.mysql.use PingMethod=false。
第二に、Spring Bootプロジェクトでは、以下のような静的なコードを起動クラスに追加することができます。
なぜ空き時間が60秒以上あるかを確認します。
推測では、アリがデータベースに設定したデータベースの空き待ち時間は60秒で、mysqlデータベースが空き時間になると空き時間の接続をオフにして、データベースサーバの処理能力を向上させます。
MySQLのデフォルトの空き時間は8時間で、「wait_」です。timeout」の設定値です。データベースが空いている接続を自動的にオフにすると、接続池が分かりません。まだこの接続を使っていると、異常が発生します。
以上がSpring Boot統合Druidに異常が発生した原因と解決の詳細です。Spring Boot統合Druidに異常が発生した資料について、他の関連記事に注目してください。
Spring Boot統合Druidプロジェクトにおいて、エラーログには以下のようなエラーメッセージが頻繁に表示されていることが分かりました。
discard long time none received connection. , jdbcUrl : jdbc:mysql://******?useSSL=false&allowPublicKeyRetrieval=true&useUnicode=true&characterEncoding=UTF-8, version : 1.2.3, lastPacketReceivedIdleMillis : 172675
調査の結果、ドライドバージョンによる異常は1.2.2及び以前のバージョンでは発生していませんでした。これらのバージョンにはこの問題があります。異常原因と解決策を分析します。異常分析
まず上の異常はプログラムの正常な運行に影響しませんが、プログラマーとしてはプログラムに異常があることを見て耐えられません。だから、根掘り葉掘り聞いて解決します。
スタック情報を追跡すると、対応の異常がcomp.alibababa.druid.pool.DruidAbstract Data Source咻testConnection Internalメソッドから投げられたもので、対応するコードは以下の通りです。
if (valid && isMySql) { // unexcepted branch
long lastPacketReceivedTimeMs = MySqlUtils.getLastPacketReceivedTimeMs(conn);
if (lastPacketReceivedTimeMs > 0) {
long mysqlIdleMillis = currentTimeMillis - lastPacketReceivedTimeMs;
if (lastPacketReceivedTimeMs > 0 //
&& mysqlIdleMillis >= timeBetweenEvictionRunsMillis) {
discardConnection(holder);
String errorMsg = "discard long time none received connection. "
+ ", jdbcUrl : " + jdbcUrl
+ ", jdbcUrl : " + jdbcUrl
+ ", lastPacketReceivedIdleMillis : " + mysqlIdleMillis;
LOG.error(errorMsg);
return false;
}
}
}
上記のコードの中で、MySQlUtils.getLastPacketReceivedTimeMsは前回使用した時間を取得します。mysql IdleMillisは暇な時間を計算します。timeBetweenEnitionRunsは定数60秒です。接続が60秒以上空きましたら、discardConnectionはこの古い接続を破棄してログLOG.warnを印刷しました。原理追跡
上記のコードの中で、私達はこの業務のロジックに入るのが前提条件があるので、つまりvalidとisMySql変数は同時にtrueです。isMySqlはtrueのために必要です。私たちが使っているのはMysqlデータベースです。では、validをfalseにしてもいいですか?このようにすれば、この業務に入ることができなくなりますか?
validのソースを見に来ましたか?それともこの方法の上ですか?
boolean valid = validConnectionChecker.isValidConnection(conn, validationQuery, validationQueryTimeout);
私たちはvalidConnection CheckerのMysql実現サブクラスMySql ValidConneckerを見つけました。このクラスの中でisValidConnectionの実現は以下の通りです。
public boolean isValidConnection(Connection conn, String validateQuery, int validationQueryTimeout) throws Exception {
if (conn.isClosed()) {
return false;
}
if (usePingMethod) {
if (conn instanceof DruidPooledConnection) {
conn = ((DruidPooledConnection) conn).getConnection();
}
if (conn instanceof ConnectionProxy) {
conn = ((ConnectionProxy) conn).getRawObject();
}
if (clazz.isAssignableFrom(conn.getClass())) {
if (validationQueryTimeout <= 0) {
validationQueryTimeout = DEFAULT_VALIDATION_QUERY_TIMEOUT;
}
try {
ping.invoke(conn, true, validationQueryTimeout * 1000);
} catch (InvocationTargetException e) {
Throwable cause = e.getCause();
if (cause instanceof SQLException) {
throw (SQLException) cause;
}
throw e;
}
return true;
}
}
String query = validateQuery;
if (validateQuery == null || validateQuery.isEmpty()) {
query = DEFAULT_VALIDATION_QUERY;
}
Statement stmt = null;
ResultSet rs = null;
try {
stmt = conn.createStatement();
if (validationQueryTimeout > 0) {
stmt.setQueryTimeout(validationQueryTimeout);
}
rs = stmt.executeQuery(query);
return true;
} finally {
JdbcUtils.close(rs);
JdbcUtils.close(stmt);
}
}
上記の方法には3つの戻りが見られます。最初の接続がオフになりました。二つ目はpingの形式を使って検査を行います。第三に、select 1の方式で検査を行います。pingの形式で検査すると、異常を投げてもtrueに戻ります。ここではこのモードを無効にすればいいです。pingに入る業務ロジックは主に変数usePingMethodによって判断されます。追跡コードはここで行われている設定を発見します。
public void configFromProperties(Properties properties) {
String property = properties.getProperty("druid.mysql.usePingMethod");
if ("true".equals(property)) {
setUsePingMethod(true);
} else if ("false".equals(property)) {
setUsePingMethod(false);
}
}
つまり、システム属性druid.mysql.use PingMethodをfalseに設定すれば、この機能を無効にできます。Ping Methodを無効にします
問題の根源を見つけたら、残りはどうやって無効にしますか?
第一に、プログラムを起動する時に運転パラメータの中で増加します。-Ddruid.mysql.use PingMethod=false。
第二に、Spring Bootプロジェクトでは、以下のような静的なコードを起動クラスに追加することができます。
static {
System.setProperty("druid.mysql.usePingMethod","false");
}
第三に、クラスファイルの構成。プロジェクトのDruidConfig類に新たに追加されました。
/*
* druid :discard long time none received connection:xxx
* */
@PostConstruct
public void setProperties(){
System.setProperty("druid.mysql.usePingMethod","false");
}
これで、この機能を無効にすることができます。異常情報はもう現れません。なぜ空き時間が60秒以上あるかを確認します。
推測では、アリがデータベースに設定したデータベースの空き待ち時間は60秒で、mysqlデータベースが空き時間になると空き時間の接続をオフにして、データベースサーバの処理能力を向上させます。
MySQLのデフォルトの空き時間は8時間で、「wait_」です。timeout」の設定値です。データベースが空いている接続を自動的にオフにすると、接続池が分かりません。まだこの接続を使っていると、異常が発生します。
以上がSpring Boot統合Druidに異常が発生した原因と解決の詳細です。Spring Boot統合Druidに異常が発生した資料について、他の関連記事に注目してください。