Java / JDBC / MySQL:如何解决为什么DriverManager.getConnection()返回NULL?

时间:2013-02-15 16:08:37

标签: java mysql jdbc

我正在尝试解决使用JDBC连接到MySQL数据库的Java应用程序的问题。表面问题是,当连接到有效的数据库时,DriverManager.getConnection有时会返回NULL,而几分钟后它将返回到完全相同的数据库的有效连接。

我正在尝试解决此问题,但我对Java,JDBC和MySQL相遇的理解相当有限。我一直在做很多研究,但已经撞墙了,不知道从哪里去。

这是我到目前为止所做的:

  • 在Java端,我已经将代码一直跟踪到DriverManager.getConnection()。我已经确定NULL连接来自那里,但我不知道getConnection引擎盖下发生了什么。我一直在努力在网上找到对此的详尽解释。
  • 在MySQL端,我已经确认有很多可用的连接(有时大约有1000个免费连接),所以我知道我没有超过那里的最大连接数。查看日志,我能够确定在我遇到最多问题的时间范围内中断的连接数略多,但我不知道如何确定为什么这些连接被中止(做了MySQL) abort,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分 我为不具体而道歉。此应用程序是一个通常工作正常的生产应用程序。它成功处理了成千上万的连接,没有任何问题,只是这个问题会在白天随机出现,并且会在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之间的某个问题。

2 个答案:

答案 0 :(得分:7)

单个驱动程序可以为连接请求返回null,JDBC 4.1规范说明了这一点:

  

当DriverManager尝试建立连接时,它会调用该驱动程序   connect方法并传递驱动程序的URL。如果是Driver实现的话   理解URL,它将返回一个Connection对象或抛出一个SQLException   如果无法将连接发送到数据库。如果驱动程序实现   不了解URL,它将返回null。

但是,查看java.sql.DriverManager的代码(在Java 7 Update 13中),它将始终抛出SQLException消息找不到合适的驱动程序< url> 当所有可用的驱动程序返回null connect(url, properties)次来电时{/ 1}}:

//  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 Update 13中没有)。快速浏览一下Java 5 Update 22源代码,显示几乎完全相同的实现,它根本无法返回null。

您更有可能吞下异常,然后尝试使用值为null的Connection变量或字段。

另一种可能性是您没有获得与DriverManager.getConnection(url, ...)的关联,但由于上面建立的规则,DriverManager.getDriver(url).connect(...)可以返回null。如果你这样做,它可能指向Connector / J驱动程序中的错误,如果你总是使用完全相同的URL:驱动程序无法决定在某一点返回特定URL的连接,然后返回null。它应始终返回Connection或为同一网址抛出SQLException

答案 1 :(得分: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;
    }
}

编译后,使用以下命令运行它:

java -classpath .;<Connector-J driver path here> persistence.DatabaseUtils