2013-02-15 167 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驅動程序有關。

任何方向的地方,我可以從這裏去,將不勝感激。

謝謝!

編輯 - 2/15,上午10:35 CST 我很抱歉沒有更具體。這個應用程序是一個通常工作得很好的生產應用程序。它每天成功處理數萬個連接,沒有任何問題,只是這個問題會在白天的隨機時間出現,並且在發生時會持續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 2013-02-15 16:10:47

+0

聽起來好像連接(網絡)不可靠,並且您的機器並不總是連接到數據庫所在的機器,所以有時連接不能建立 – 2013-02-15 16:32:05

+0

傑夫 - 這是我的懷疑,但很難說這可能會發生。如果有一些方法可以幫助我確定DriverManager.getConnection返回NULL的不同原因,那將有助於我顯着地追蹤這個問題。 – TACHEON 2013-02-15 16:37:50

回答

7

一個單獨的驅動程序可以爲連接請求返回null,在JDBC 4.1規範是:

當DriverManager的正在嘗試建立連接,它會調用該驅動程序的連接方法 並將URL傳遞給驅動程序。如果驅動程序實現 瞭解URL,則它將返回一個Connection對象,或者如果無法將連接轉換爲數據庫,則會拋出SQLException 。如果驅動程序實現 不能理解URL,它將返回null。

然而,看着java.sql.DriverManager代碼(在Java 7中更新13),它將總是有消息發現<網址>沒有合適的驅動程序拋出SQLException當所有可用的驅動程序已經爲返回null一個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。

更可能是吞嚥異常,然後嘗試使用Connection值爲null的變量或字段。

另一種可能性是,你是不是獲得與DriverManager.getConnection(url, ...)的連接,但DriverManager.getDriver(url).connect(...)可因爲前面建立的規則返回null。如果這是你所做的,那麼如果你始終使用完全相同的URL,那麼它可能指向Connector/J驅動程序中的錯誤:驅動程序無法決定在某一點返回特定URL的連接,並且接下來返回null。它應該始終返回Connection或爲同一個網址投擲SQLException

+2

謝謝你澄清,它永遠不會返回NULL,而是一個例外。我做了更多的挖掘工作,並找到了例外情況被吞噬的地方。我已經完成了所有的代碼很多次,我不知道我是如何錯過它的。 – TACHEON 2013-02-15 17:04:55

+0

很高興能幫到你! – 2013-02-15 17:06:02

2

是,DriverManager是獲取你的連接類。

它管理這個使用你與MySQL連接器-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; 
    } 
} 

編譯後,使用此命令運行它:

java -classpath .;<Connector-J driver path here> persistence.DatabaseUtils 
相關問題