2017-09-11 1 views
1

Java Webアプリケーションには、大きなデータベースでレコードを検索できる検索機能があります。長時間実行するクエリ(MySql)、Apache Tomcat DataSourceを自動的に削除する

ユーザーが間違った検索パラメータを指定すると、実行に数時間かかるため終了しないクエリが表示されます。

これはWebアプリケーションであり、何度も試してみると、クエリが重大なパフォーマンスの問題を引き起こすすべてのリソースを突き詰めました。

実行時間が長すぎたり、CPUを多用すると、クエリを自動的に強制終了する方法はありますか?

+0

https://stackoverflow.com/questions/18253934/set-maximum-execution-time-in-mysql-php – user7294900

答えて

0

この回答はApache Tomcat-jdbc DataSource providerについてのものです。

クエリが長くsetRemoveAbandonedTimeout(int型)で指定した時間よりもかかったときPoolProperties

  1. setRemoveAbandonedTimeout

  2. の理解が

をsetRemoveAbandoned持っている必要があり、すべての

ファーストこのクエリを実行する接続はAbandonとマークされ、java.sql.Connection.close()メソッドが呼び出されます。 pは、接続を解放する前にクエリが完了するのを待っています。

放棄された接続を処理する独自のハンドラを実装できます。

PoolConfiguration.java(インターフェース)

ゲッターの追加と:以下はインタフェースに

package org.apache.tomcat.jdbc.pool; 

public interface AbandonedConnectionHandler { 

     public void handleQuery(Long connectionId); 

} 

のtomcat-JDBCファイルの変更を追加するために必要なすべての

最初に変更がありますセッターメソッド。

public void setAbandonedConnectionHandler(AbandonedConnectionHandler abandonedConnectionHandler); 

public AbandonedConnectionHandler getAbandonedConnectionHandler(); 

オーバーライドすべての実装クラス

  • DataSourceProxy.java
  • PoolProperties.javaに、これらのメソッド
  • org.apache.tomcat.jdbc.pool.jmx.ConnectionPool.java

メソッドを追加getConnectionId()org.apache.tomcat.jdbc.pool。PooledConnection.java

public Long getConnectionId() { 
    try { 
     //jdbc impl has getId() 
     Method method = this.connection.getClass().getSuperclass().getMethod("getId"); 
     return (Long)method.invoke(this.connection); 
    } catch (Exception e) { 
     log.warn(" Abandoned QueryHandler failed to initialize connection id "); 
    } 
    return null; 
} 

上記反射コードが異なるMySQLドライバの場合には異なる可能性があります。

今、私たちはorg.apache.tomcat.jdbc.pool.ConnectionPool.java

でjava.sql.Connection.close()メソッドを開始しますConnectionPool.javaメソッドを呼び出す前に、当社のハンドラを配置する必要があります中止接続クリーナーは

protected void abandon(PooledConnection con) 

リリース(CON)を呼び出す前に、このメソッド内のコードの下に追加され、今

if(getPoolProperties().getAbandonedConnectionHandler() != null) 
      { 
       con.lock(); 
       getPoolProperties().getAbandonedConnectionHandler().handleQuery(con.getConnectionId()); 
      } 

あなたがしなければならないすべては、Tomcat-JDBCデータソースを作成中PoolPropertiesと一緒にあなたのhanderInstanceを渡すことです。

p.setAbandonedConnectionHandler(new ConnectionHandler(true)); 

ここに私のAbandonedConnectionHandler実装があります。

import java.sql.Connection; 
import java.sql.DriverManager; 
import java.sql.ResultSet; 
import java.sql.SQLException; 
import java.sql.Statement; 

import org.apache.juli.logging.Log; 
import org.apache.juli.logging.LogFactory; 
import org.apache.tomcat.jdbc.pool.AbandonedConnectionHandler; 
import org.apache.tomcat.jdbc.pool.PoolConfiguration; 


public class ConnectionHandler implements AbandonedConnectionHandler{ 

    private static final Log log = LogFactory.getLog(ConnectionHandler.class); 

    private Boolean isAllowedToKill;  
    private PoolConfiguration poolProperties; 

    public ConnectionHandler(Boolean isAllowedToKill) 
    { 
     this.isAllowedToKill = isAllowedToKill; 
    } 

    @Override 
    public void handleQuery(Long connectionId) { 
     Connection conn = null; 
     Statement stmt = null; 
     if(this.isAllowedToKill) 
     { 
      try{ 

       Class.forName(poolProperties.getDriverClassName()); 
       conn = DriverManager.getConnection(poolProperties.getUrl(),poolProperties.getUsername(),poolProperties.getPassword()); 

       Statement statement = conn.createStatement(); 
       ResultSet result = statement.executeQuery("SELECT ID, INFO, USER, TIME FROM information_schema.PROCESSLIST WHERE ID=" + connectionId); 

       if(result.next()) 
       { 
        if(isFetchQuery(result.getString(2))) 
        { 
         statement.execute("Kill "+connectionId); 
        } 

       } 
       statement.close(); 
       conn.close(); 
      } 
      catch(Exception e) 
      { 
       e.printStackTrace(); 
      } 
      finally 
      { 
       try { 
        if(stmt != null && !stmt.isClosed()) 
        stmt.close(); 
       } catch (SQLException e) { 
        log.warn("Exception while closing Statement "); 
       } 
       try { 
        if(conn != null && !conn.isClosed()) 
        conn.close(); 
       } catch (SQLException e) { 
        log.warn("Exception while closing Connection "); 
       } 
      } 
     } 
    } 
    private Boolean isFetchQuery(String query) 
    { 
     if(query == null) 
     { 
      return true; 
     } 
     query = query.trim(); 
     return "SELECT".equalsIgnoreCase(query.substring(0, query.indexOf(' '))); 
    } 

    public PoolConfiguration getPoolProperties() { 
     return poolProperties; 
    } 
    public void setPoolProperties(PoolConfiguration poolProperties) { 
     this.poolProperties = poolProperties; 
    } 

} 
0

あなたにとって最良の選択肢は、実行できない検索条件をキャッチすることです。

5.7.8からMySQLには、max_execution_time settingがあります。

また、SHOW PROCESSLISTをチェックし、制限時間を超えて処理されているクエリを処理するcronスクリプトを用意することもできます。

関連する問題