我正在尝试解决使用JDBC连接到MySQL数据库的Java应用程序的问题。表面问题是,当连接到有效的数据库时,DriverManager.getConnection有时会返回NULL,而几分钟后它将返回到完全相同的数据库的有效连接。
我正在尝试解决此问题,但我对Java,JDBC和MySQL相遇的理解相当有限。我一直在做很多研究,但已经撞墙了,不知道从哪里去。
这是我到目前为止所做的:
任何关于我可以从这里离开的方向都会非常感激。
谢谢!
编辑 - 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之间的某个问题。
答案 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