2013-02-15 26 views
5

Tôi đang cố khắc phục sự cố với ứng dụng Java đang sử dụng JDBC để kết nối với cơ sở dữ liệu MySQL. Vấn đề bề mặt là khi kết nối với một cơ sở dữ liệu hợp lệ, DriverManager.getConnection đôi khi sẽ trả về NULL, trong khi chỉ một vài phút sau nó sẽ trả về một kết nối hợp lệ cho cùng một cơ sở dữ liệu.Java/JDBC/MySQL: Làm cách nào để khắc phục sự cố tại sao DriverManager.getConnection() trả về NULL?

Tôi đang ở vị trí của cố gắng để khắc phục vấn đề này, nhưng hiểu biết của tôi về nơi Java, JDBC, và MySQL gặp nhau là khá hạn chế. Tôi đã làm rất nhiều nghiên cứu về điều này, nhưng đã đánh một bức tường và không biết đi đâu từ đây.

Dưới đây là những gì tôi đã làm như vậy cho đến nay:

  • Trên cuối Java, tôi đã bắt nguồn từ mã tất cả các cách để DriverManager.getConnection(). Tôi đã xác định rằng kết nối NULL là đến từ đó, nhưng tôi không có đầu mối những gì diễn ra dưới mui xe của getConnection. Tôi đã đấu tranh để tìm một giải thích kỹ lưỡng về điều này trực tuyến.
  • Khi kết thúc MySQL, tôi đã xác minh rằng có rất nhiều kết nối có sẵn cho tôi (khoảng 1000 kết nối miễn phí), vì vậy tôi biết tôi không vượt quá các kết nối tối đa ở đó. Xem nhật ký, tôi đã có thể xác định rằng có số lượng kết nối bị hủy bỏ cao hơn một chút trong khung thời gian mà tôi gặp phải nhiều sự cố nhất, nhưng tôi không biết cách xác định lý do tại sao các kết nối này bị hủy bỏ (đã làm MySQL) abort, JDBC, ứng dụng Java?) Tôi không chắc liệu có bất cứ điều gì khác mà tôi cần phải tìm kiếm vào cuối MySQL không.
  • Ở giữa, với JDBC, tôi khá lạc. Tôi đã được đọc trên MySQL Connector/J tại http://dev.mysql.com/doc/refman/5.1/en/connector-j.html, nhưng tôi không chắc chắn nếu thông tin đó liên quan đến trình điều khiển JDBC đang được sử dụng bởi Java.

Bất kỳ hướng nào đến nơi tôi có thể đi từ đây sẽ được đánh giá cao.

Cảm ơn!

EDIT - 2/15, 10:35 am CST Tôi xin lỗi vì không cụ thể hơn. Ứng dụng này là một ứng dụng sản xuất thường hoạt động tốt. Nó xử lý thành công hàng chục ngàn kết nối mỗi ngày mà không có bất kỳ vấn đề nào, chỉ là vấn đề này sẽ xáo trộn vào những thời điểm ngẫu nhiên trong ngày và sẽ tồn tại trong khoảng từ 30 giây đến 5 phút khi nó xảy ra.

Dưới đây là đoạn code mà tôi đã bắt nguồn từ tất cả các con đường xuống 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); 
    } 

Tôi không tin rằng có thực sự là bất kỳ vấn đề với mã, mà là một vấn đề ở đâu đó ở giữa getConnection() và MySQL.

+1

Đăng một số mã và sẽ giúp bạn dễ dàng hơn. – duffymo

+0

có vẻ như kết nối (mạng) không đáng tin cậy và máy của bạn không phải lúc nào cũng kết nối với máy mà db đang bật, vì vậy đôi khi kết nối không thể được thiết lập –

+0

Jeff - Đó là sự nghi ngờ của tôi, nhưng rất khó để nói nơi điều này có thể xảy ra. Nếu có một số cách để tôi xác định các lý do khác nhau tại sao DriverManager.getConnection sẽ trả về NULL, điều đó sẽ giúp tôi theo dõi vấn đề này một cách đáng kể. – TACHEON

Trả lời

7

Một tài xế cá nhân có thể trở về null cho một yêu cầu kết nối, các JDBC 4.1 đặc điểm kỹ thuật nói điều này:

Khi DriverManager đang cố gắng thiết lập kết nối, nó gọi phương thức kết nối của trình điều khiển và chuyển cho trình điều khiển URL. Nếu việc thực hiện trình điều khiển hiểu URL, nó sẽ trả về một đối tượng kết nối hoặc ném một SQLException nếu kết nối không thể bị làm điên lên cơ sở dữ liệu. Nếu việc triển khai Trình điều khiển thực hiện không hiểu URL, nó sẽ trả về giá trị rỗng.

Tuy nhiên, nhìn vào mã của java.sql.DriverManager (trong Java 7 Update 13), nó sẽ luôn ném một SQLException với thông điệp Không lái xe phù hợp tìm thấy cho <url> khi tất cả các trình điều khiển có sẵn đã trở null cho a connect(url, properties) gọi:

// 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"); 
} 

Nói cách khác: những gì bạn mô tả không thể xảy ra (ít nhất là không có trong Java 7 Update 13). Xem nhanh các nguồn Java 5 Update 22 cho thấy việc triển khai gần như giống hệt nhau là nó không thể trả về null.

Nhiều khả năng bạn đang nuốt một ngoại lệ và sau đó cố gắng sử dụng biến số Connection hoặc trường có giá trị null.

Một khả năng khác là bạn không có kết nối với DriverManager.getConnection(url, ...), nhưng với DriverManager.getDriver(url).connect(...) có thể trả về null vì các quy tắc được thiết lập ở trên. Nếu đó là những gì bạn làm, nó có thể trỏ đến một lỗi trong trình điều khiển Connector/J nếu bạn luôn sử dụng cùng một URL chính xác: một trình điều khiển không thể quyết định tại một điểm để trả về kết nối cho một URL cụ thể và null trả về tiếp theo. Nó phải luôn trả về một số Connection hoặc ném SQLException cho cùng một URL.

+2

Cảm ơn bạn đã làm rõ rằng nó sẽ không bao giờ trả về NULL, mà là một ngoại lệ. Tôi đã làm một số đào nhiều hơn và tìm thấy nơi ngoại lệ đang được nuốt vào. Tôi đã được trên tất cả các mã rất nhiều lần tôi không chắc chắn làm thế nào tôi bị mất nó. – TACHEON

+0

Vui vì tôi có thể giúp! –

2

Vâng, DriverManager là lớp mà được kết nối cho bạn.

Nó quản lý này bằng cách sử dụng các lớp điều khiển JDBC mà bạn nhận được với các JAR MySQL Connector-J. JAR đó phải nằm trong số CLASSPATH của bạn khi bạn bắt đầu.

Bắt đầu bằng cách đảm bảo bạn có thể kết nối với MySQL từ máy nơi bạn chạy ứng dụng Java. Đăng nhập vào ứng dụng quản trị MySQL thành công và bạn đã vượt qua rào cản đầu tiên.

Tôi sẽ cung cấp cho bạn một lớp học cho bác sĩ về tình trạng của bạn. Các phương pháp này có thể hữu ích cho bạn.Sửa đổi kết nối, thông tin xác thực và truy vấn cho tình huống của bạn và dùng thử. Tôi biết mã này hoạt động.

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; 
    } 
} 

Sau khi biên dịch, chạy nó bằng lệnh này:

java -classpath .;<Connector-J driver path here> persistence.DatabaseUtils 
Các vấn đề liên quan