2013-02-15 24 views
5

JDBCを使用してMySQLデータベースに接続しているJavaアプリケーションの問題をトラブルシューティングしようとしています。表面の問題は、有効なデータベースに接続すると、DriverManager.getConnectionがNULLを返すことがあります。ほんの数分後に、同じデータベースに有効な接続が返されることがあります。Java/JDBC/MySQL:DriverManager.getConnection()がNULLを返す理由をトラブルシューティングするにはどうすればよいですか?

私はこの問題のトラブルシューティングを試みる立場にありますが、Java、JDBC、およびMySQLがどこで会うのかについての私の理解はかなり制限されています。私はこれについて多くの研究をしてきましたが、壁に衝突し、ここからどこに行くのか分かりません。ここで

は、私がこれまで何をやったかです:

  • のJava側では、私は()のコードにしたDriverManager.getConnectionにすべての方法をトレースしています。私はそこからNULL接続が来ていると判断しましたが、getConnectionのフードの下で何が起こっているのかわかりません。私はこのオンラインの完全な説明を見つけるのに苦労してきました。
  • MySQLの終わりに、私は利用可能な接続がたくさんあることを確認しました。(約1000回の無料接続があります)、最大接続数を超えていません。ログを見ると、問題が最も多い時間帯に中断しているコネクション数が少し増えたと判断できましたが、なぜこれらの接続が中止されたのかを判断する方法がわかりません(MySQL中止、JDBC、Javaアプリケーション?)私はMySQLの終わりで探している必要があるかどうかはわかりません。
  • 真ん中では、JDBCではかなり失われています。私はhttp://dev.mysql.com/doc/refman/5.1/en/connector-j.htmlでMySQL Connector/Jを読んできましたが、その情報がJavaで利用されているJDBCドライバに関係しているかどうかは不明です。

私がここからどこに行くことができるかについてのどんな方向も大いに感謝するでしょう。

ありがとうございます!

EDIT - 2/15、10:35 am CST より具体的ではないことをお詫び申し上げます。このアプリケーションは正常に動作するプロダクションアプリケーションです。 1日に数万件の接続を問題なく処理することができます。この問題は、1日のうちにランダムな時間帯に発生し、30秒から5分まで持続します。

ここで私はすべての方法ダウンしたDriverManager.getConnectionにトレースしたコードです:

var dbConn = DatabaseConnectionFactory.createDatabaseConnection('com.mysql.jdbc.Driver','jdbc:mysql://'+ serverName +':' + port + '/' + database, userName, password); 

public static DatabaseConnection createDatabaseConnection(String driver, String address, String username, String password) throws SQLException { 
     try { 
      Class.forName(driver); 
     } catch (Exception e) { 
      e.printStackTrace(); 
     } 

     Properties info = new Properties(); 
     info.setProperty("user", username); 
     info.setProperty("password", password); 

     // this property should only be set if it's for embedded database 
     info.setProperty("shutdown", "true"); 

     return new DatabaseConnection(address, info); 
    } 

public DatabaseConnection(String address, Properties info) throws SQLException { 
     logger.debug("creating new database connection: address=" + address + ", " + info); 
     this.address = address; 
     connection = DriverManager.getConnection(address, info); 
    } 

私はコードですべての問題ではなく、問題がどこかのgetConnectionの間で実際にそこにあるとは思わないが、 ()とMySQL。

+1

いくつかのコードを投稿すると、より簡単にお手伝いします。 – duffymo

+0

接続(ネットワーク)が信頼できない可能性があり、マシンが常にdbに接続されているマシンに接続されていない可能性があるので、接続が確立できない場合があります。 –

+0

Jeff - これは私の疑いですが、これが発生している可能性があります。 DriverManager.getConnectionがNULLを返すさまざまな理由を判断する方法がある場合は、この問題を大幅に追跡するのに役立ちます。 – TACHEON

答えて

7

は、JDBC 4.1仕様では、この意見:

ときにDriverManagerを接続を確立しようとしているときに、そのドライバの メソッドを呼び出してドライバにURLを渡します。ドライバの実装 がURLを認識した場合、データベースに接続できない場合はConnectionオブジェクトが返されるか、SQLException がスローされます。ドライバ実装が にURLを認識しない場合、nullを返します。利用可能なすべてのドライバがためnullを返したとき

しかし、java.sql.DriverManagerのコードを見て(Javaの7の更新13で)、それは、常には、メッセージ<URL>が見つかりません、適切なドライバでSQLExceptionをスローしますconnect(url, properties)コール:

// Worker method called by the public getConnection() methods. 
private static Connection getConnection(
    String url, java.util.Properties info, ClassLoader callerCL) throws SQLException { 
// Removed some classloading stuff for brevity 
    if(url == null) { 
     throw new SQLException("The url cannot be null", "08001"); 
    } 
    // Walk through the loaded registeredDrivers attempting to make a connection. 
    // Remember the first exception that gets raised so we can reraise it. 
    SQLException reason = null; 
    for(DriverInfo aDriver : registeredDrivers) { 
     // If the caller does not have permission to load the driver then 
     // skip it. 
     if(isDriverAllowed(aDriver.driver, callerCL)) { 
      try { 
       println(" trying " + aDriver.driver.getClass().getName()); 
       Connection con = aDriver.driver.connect(url, info); 
       if (con != null) { 
        // Success! 
        println("getConnection returning " + aDriver.driver.getClass().getName()); 
        return (con); 
       } 
      } catch (SQLException ex) { 
       if (reason == null) { 
        reason = ex; 
       } 
      } 
     } else { 
      println(" skipping: " + aDriver.getClass().getName()); 
     } 
    } 
    // if we got here nobody could connect. 
    if (reason != null) { 
     println("getConnection failed: " + reason); 
     throw reason; 
    } 
    println("getConnection: no suitable driver found for "+ url); 
    throw new SQLException("No suitable driver found for "+ url, "08001"); 
} 

言い換えれば:あなたが記述するものは、(少なくともではないのJava 7の更新13に)発生することはできません。 Java 5 Update 22のソースでは、単純にnullを返すことができないという点で、ほぼ同じ実装を示しています。

例外を飲み込んで、値がnullの変数またはフィールドConnectionを使用しようとしている可能性があります。

もう一つの可能​​性は、あなたがDriverManager.getConnection(url, ...)との接続を取得されていませんが、DriverManager.getDriver(url).connect(...)であるため上記の確立されたルールのnullを返すことができたということでしょう。それがあなたのやり方であれば、常に同じURLを使用している場合は、Connector/Jドライバのバグを指摘しているはずです。ドライバは特定のURLへの接続を返してからnullを返すことはできません。 Connectionを返すか、同じURLに対してSQLExceptionを投げるかのどちらかです。

+2

これはNULLを返すことはないが、代わりに例外を返すことを明確にしてくれてありがとう。私はもう少し掘り下げて、例外がどこで飲み込まれているのかを見つけました。私はすべてのコードを何度も読んできたので、私はそれを見逃してしまったのか分かりません。 – TACHEON

+0

うれしい私は助けることができました! –

2

はい、DriverManagerは接続を取得するクラスです。

これは、MySQL Connector-J JARを使用して取得したJDBCドライバクラスを使用してこれを管理します。そのJARは、起動時にCLASSPATHになければなりません。

まず、Javaアプリケーションを実行しているマシンからMySQLに接続できることを確認してください。 MySQL管理アプリケーションに正常にログインすると、最初のハードルを過ぎたことになります。

あなたの状況に合わせて医師にクラスを提供します。これらのメソッドは、一般的にあなたにとって役に立ちます。状況に合わせて接続、資格情報、およびクエリを変更し、試してみてください。私はを知っていますこのコードは動作します。このコマンドでそれを実行してコンパイルした後

package persistence; 

import java.sql.*; 
import java.util.*; 

/** 
* util.DatabaseUtils 
* User: Michael 
* Date: Aug 17, 2010 
* Time: 7:58:02 PM 
*/ 
public class DatabaseUtils { 
/* 
    private static final String DEFAULT_DRIVER = "oracle.jdbc.driver.OracleDriver"; 
    private static final String DEFAULT_URL = "jdbc:oracle:thin:@host:1521:database"; 
    private static final String DEFAULT_USERNAME = "username"; 
    private static final String DEFAULT_PASSWORD = "password"; 
*/ 
/* 
    private static final String DEFAULT_DRIVER = "org.postgresql.Driver"; 
    private static final String DEFAULT_URL = "jdbc:postgresql://localhost:5432/party"; 
    private static final String DEFAULT_USERNAME = "pgsuper"; 
    private static final String DEFAULT_PASSWORD = "pgsuper"; 
*/ 
    private static final String DEFAULT_DRIVER = "com.mysql.jdbc.Driver"; 
    private static final String DEFAULT_URL = "jdbc:mysql://localhost:3306/party"; 
    private static final String DEFAULT_USERNAME = "party"; 
    private static final String DEFAULT_PASSWORD = "party"; 

    public static void main(String[] args) { 
     long begTime = System.currentTimeMillis(); 

     String driver = ((args.length > 0) ? args[0] : DEFAULT_DRIVER); 
     String url = ((args.length > 1) ? args[1] : DEFAULT_URL); 
     String username = ((args.length > 2) ? args[2] : DEFAULT_USERNAME); 
     String password = ((args.length > 3) ? args[3] : DEFAULT_PASSWORD); 

     Connection connection = null; 

     try { 
      connection = createConnection(driver, url, username, password); 
      DatabaseMetaData meta = connection.getMetaData(); 
      System.out.println(meta.getDatabaseProductName()); 
      System.out.println(meta.getDatabaseProductVersion()); 

      String sqlQuery = "SELECT PERSON_ID, FIRST_NAME, LAST_NAME FROM PERSON ORDER BY LAST_NAME"; 
      System.out.println("before insert: " + query(connection, sqlQuery, Collections.EMPTY_LIST)); 

      connection.setAutoCommit(false); 
      String sqlUpdate = "INSERT INTO PERSON(FIRST_NAME, LAST_NAME) VALUES(?,?)"; 
      List parameters = Arrays.asList("Foo", "Bar"); 
      int numRowsUpdated = update(connection, sqlUpdate, parameters); 
      connection.commit(); 

      System.out.println("# rows inserted: " + numRowsUpdated); 
      System.out.println("after insert: " + query(connection, sqlQuery, Collections.EMPTY_LIST)); 
     } catch (Exception e) { 
      rollback(connection); 
      e.printStackTrace(); 
     } finally { 
      close(connection); 
      long endTime = System.currentTimeMillis(); 
      System.out.println("wall time: " + (endTime - begTime) + " ms"); 
     } 
    } 

    public static Connection createConnection(String driver, String url, String username, String password) throws ClassNotFoundException, SQLException { 
     Class.forName(driver); 
     if ((username == null) || (password == null) || (username.trim().length() == 0) || (password.trim().length() == 0)) { 
      return DriverManager.getConnection(url); 
     } else { 
      return DriverManager.getConnection(url, username, password); 
     } 
    } 

    public static void close(Connection connection) { 
     try { 
      if (connection != null) { 
       connection.close(); 
      } 
     } catch (SQLException e) { 
      e.printStackTrace(); 
     } 
    } 


    public static void close(Statement st) { 
     try { 
      if (st != null) { 
       st.close(); 
      } 
     } catch (SQLException e) { 
      e.printStackTrace(); 
     } 
    } 

    public static void close(ResultSet rs) { 
     try { 
      if (rs != null) { 
       rs.close(); 
      } 
     } catch (SQLException e) { 
      e.printStackTrace(); 
     } 
    } 

    public static void rollback(Connection connection) { 
     try { 
      if (connection != null) { 
       connection.rollback(); 
      } 
     } catch (SQLException e) { 
      e.printStackTrace(); 
     } 
    } 

    public static List<Map<String, Object>> map(ResultSet rs) throws SQLException { 
     List<Map<String, Object>> results = new ArrayList<Map<String, Object>>(); 
     try { 
      if (rs != null) { 
       ResultSetMetaData meta = rs.getMetaData(); 
       int numColumns = meta.getColumnCount(); 
       while (rs.next()) { 
        Map<String, Object> row = new HashMap<String, Object>(); 
        for (int i = 1; i <= numColumns; ++i) { 
         String name = meta.getColumnName(i); 
         Object value = rs.getObject(i); 
         row.put(name, value); 
        } 
        results.add(row); 
       } 
      } 
     } finally { 
      close(rs); 
     } 
     return results; 
    } 

    public static List<Map<String, Object>> query(Connection connection, String sql, List<Object> parameters) throws SQLException { 
     List<Map<String, Object>> results = null; 
     PreparedStatement ps = null; 
     ResultSet rs = null; 
     try { 
      ps = connection.prepareStatement(sql); 

      int i = 0; 
      for (Object parameter : parameters) { 
       ps.setObject(++i, parameter); 
      } 
      rs = ps.executeQuery(); 
      results = map(rs); 
     } finally { 
      close(rs); 
      close(ps); 
     } 
     return results; 
    } 

    public static int update(Connection connection, String sql, List<Object> parameters) throws SQLException { 
     int numRowsUpdated = 0; 
     PreparedStatement ps = null; 
     try { 
      ps = connection.prepareStatement(sql); 

      int i = 0; 
      for (Object parameter : parameters) { 
       ps.setObject(++i, parameter); 
      } 
      numRowsUpdated = ps.executeUpdate(); 
     } finally { 
      close(ps); 
     } 
     return numRowsUpdated; 
    } 
} 

、:個々のドライバーは、接続要求のためにnullを返すことができ

java -classpath .;<Connector-J driver path here> persistence.DatabaseUtils 
関連する問題