常見問題和解決方案
對于MySQL Connector/J用戶,會遇到一些常見的共同問題。在本節中,介紹了它們的癥狀和相應的解決方法。 關于更進一步的信息,請參見“支持”一節。
問題:
當我嘗試用MySQL Connector/J連接到數據庫時,遇到下述異常:
SQLException: Server configuration denies access to data source
SQLState: 08001
VendorError: 0
出現了什么問題? 使用MySQL命令行客戶端時,連接良好。
回答:
MySQL Connector/J必須使用TCP/IP套接字來連接MySQL,原因在于Java不支持Unix Domain套接字。因此,當MySQL Connector/J連接到MySQL時,MySQL服務器的安全管理器將使用其授權表判斷是否允許連接。必須添加授權才能允許該操作。下面給出了一個執行該操作的示例(但并非最安全的)。
從mysql命令行客戶端以能夠授權的用戶身份登錄,并發出下述命令:
GRANT ALL PRIVILEGES ON [dbname].* to
'[user]'@'[hostname]' identified by
'[password]'
用你的數據庫名稱替換[dbname],用用戶名替換[user],用MySQL Connector/J將連接的主機替換[hostname],并用打算使用的密碼替換[password]。注意,對于從本地主機進行連接的主機名部分,RedHat Linux將失敗。在這種情況下,對于[hostname]值,需要使用“localhost.localdomain”。隨后,發出FLUSH PRIVILEGES命令。
注釋:
除非添加了“--host”標志,并為主機使用了不同于“localhost”的其他設置,否則將無法使用mysql命令行客戶端測試連通性。如果使用了特殊的主機名“localhost”,mysql命令行客戶端將使用Unix域套接字。如果正在測試與“localhost”的連通性,請使用 “127.0.0.1”作為主機名。
警告
如果你不了解“GRANT”命令是干什么的,或不了解該命令的工作方式,在嘗試更改權限之前,請閱讀MySQL手冊中的 一般安全事宜以及MySQL訪問權限體系一節。
如果在MySQL中不恰當地更改了權限和許可,可能會使服務器不會具有最佳的安全性能。
問題:
我的應用程序拋出SQLException“無恰當的驅動程序”。為什么會出現該情況?
回答:
出現了兩種情況之一。或是1驅動程序未位于你的CLASSPATH中(請參見前面的“安裝部分”),或是URL格式不正確(請參見用MySQL Connector/J開發應用程序)。
問題:
當我試圖在Java程序或應用程序中使用MySQL Connector/J時,遇到類似下面的異常:
SQLException: 無法連接到host:3306上的MySQL服務器。
在你嘗試連接的機器/端口上是否有正在運行的MySQL服務器?
(java.security.AccessControlException)
SQLState: 08S01
VendorError: 0
回答:
或許是因為你正在運行Applet,你的MySQL服務器是采用“--skip-networking”選項集安裝的;或許是因為MySQL服務器位于防火墻之后。
Applet僅能使網絡連接返回運行Web服務器的機器,該Web服務器提供了用于Applet的.class文件。這意味著,要想使其工作, MySQL 必須運行在相同的機器上(或必須使某類端口重定向)。這還意味著,你無法通過你的本地文件系統來測試Java程序,你必須將它們放在Web服務器上。
MySQL Connector/J僅能使用TCP/IP與MySQL進行通信,這是因為Java不支持Unix域套接字。如果MySQL是用“--skip-networking”標志啟動的,或采用了防火墻,TCP/IP與MySQL的通信可能會受到影響。
如果MySQL是用“--skip-networking”選項集啟動的(例如MySQL服務器的Debian Linux包即用于該目的),需要在文件/etc/mysql/my.cnf或/etc/my.cnf中將其注釋掉。當然,my.cnf文件也可能位于 MySQl服務器的“data”目錄下或其他地方(取決于系統中MySQL的編譯方式)。MySQL AB創建的二進制文件總會在查找/etc/my.cnf和[datadir]/my.cnf。如果為MySQL服務器部署了防火墻,需要對防火墻進行配置,允許從運行Java代碼的主機在MySQL監聽的端口上(默認為3306)建立與 MySQL服務器的TCP/IP連接。
問題:
I我的小服務程序/應用程序白天工作良好,但在晚上卻停止工作。
回答:
不工作時間超過8小時后,MySQL關閉了連接。你或許需要使用能處理失效連接的連接池,或使用“autoReconnect”參數(請參見用MySQL Connector/J開發應用程序)。
此外,你應在應用程序中俘獲 SQLException并處理它們,而不是在應用程序退出前一直傳播它們,這是1個好的編程習慣。在查詢處理過程中遇到網絡連通性方面的問題時, MySQL Connector/J會將SQLState(參見APIDOCS中的java.sql.SQLException.getSQLState())設置為 “08S01”。隨后,應用程序代碼將嘗試再次連接到MySQL。
在下面的示例(simplistic)中,給出了能夠處理這類異常的代碼:
重試邏輯的事務示例
public void doBusinessOp() throws SQLException {
Connection conn = null;
Statement stmt = null;
ResultSet rs = null;
//
// How many times do you want to retry the transaction
// (or at least _getting_ a connection)?
//
int retryCount = 5;
boolean transactionCompleted = false;
do {
try {
conn = getConnection(); // assume getting this from a
// javax.sql.DataSource, or the
// java.sql.DriverManager
conn.setAutoCommit(false);
//
// Okay, at this point, the 'retry-ability' of the
// transaction really depends on your application logic,
// whether or not you're using autocommit (in this case
// not), and whether you're using transacational storage
// engines
//
// For this example, we'll assume that it's _not_ safe
// to retry the entire transaction, so we set retry count
// to 0 at this point
//
// If you were using exclusively transaction-safe tables,
// or your application could recover from a connection going
// bad in the middle of an operation, then you would not
// touch 'retryCount' here, and just let the loop repeat
// until retryCount == 0.
//
retryCount = 0;
stmt = conn.createStatement();
String query = "SELECT foo FROM bar ORDER BY baz";
rs = stmt.executeQuery(query);
while (rs.next()) {
}
rs.close();
rs = null;
stmt.close();
stmt = null;
conn.commit();
conn.close();
conn = null;
transactionCompleted = true;
} catch (SQLException sqlEx) {
//
// The two SQL states that are 'retry-able' are 08S01
// for a communications error, and 41000 for deadlock.
//
// Only retry if the error was due to a stale connection,
// communications problem or deadlock
//
String sqlState = sqlEx.getSQLState();
if ("08S01".equals(sqlState) || "41000".equals(sqlState)) {
retryCount--;
} else {
retryCount = 0;
}
} finally {
if (rs != null) {
try {
rs.close();
} catch (SQLException sqlEx) {
// You'd probably want to log this . . .
}
}
if (stmt != null) {
try {
stmt.close();
} catch (SQLException sqlEx) {
// You'd probably want to log this as well . . .
}
}
if (conn != null) {
try {
//
// If we got here, and conn is not null, the
// transaction should be rolled back, as not
// all work has been done
try {
conn.rollback();
} finally {
conn.close();
}
} catch (SQLException sqlEx) {
//
// If we got an exception here, something
// pretty serious is going on, so we better
// pass it up the stack, rather than just
// logging it. . .
throw sqlEx;
}
}
}
} while (!transactionCompleted && (retryCount > 0));
}
問題:
我正嘗試使用JDBC-2.0可更新結果集,但遇到異常,說我的結果集不可更新。
回答:
由于MySQL沒有行ID,MySQL Connector/J僅能更新來自查詢且位于有至少一個主鍵的表上的結果集,查詢必須選擇所有的主鍵,而且查詢即能作用在1個表上(即不存在聯合)。在JDBC規范中給出了這方面的介紹。