Java JDBC 使用 SQLite/改進
上一頁的程式碼雖然可以使用,但它很笨拙,更像是面向過程的,而不是面向物件的。通常在實際情況中,特定於資料庫的程式碼將位於它自己的類中,然後根據需要建立和使用作為獨立的物件。
讓我們看一下我們如何考慮這樣做。
import java.sql.ResultSet;
public class BetterHelloDatabase
{
public static void main (String[] args)
{
String sDropTable = "DROP TABLE IF EXISTS dummy";
String sMakeTable = "CREATE TABLE dummy (id numeric, response text)";
String sMakeInsert = "INSERT INTO dummy VALUES(1,'Hello from the database')";
String sMakeSelect = "SELECT response from dummy";
String sDriver = "jdbc:sqlite";
String sDatabaseToUse = "hello.db";
String sDbUrl = sDriver + ":" + sDatabaseToUse;
DbClass db = new DbClass(sDbUrl);
try {
db.execute(sDropTable);
db.execute(sMakeTable);
db.execute(sMakeInsert);
ResultSet rs = db.executeQuery(sMakeSelect);
try {
while(rs.next())
{
String sResult = rs.getString("response");
System.out.println(sResult);
}
} finally {
try { rs.close(); } catch (Exception ignore) {}
}
} finally {
try { db.close(); } catch (Exception ignore) {}
}
}
}
這是一個對上一節的改進,因為我們現在可以透過例項化提出的新類 DbClass 來擁有多個數據庫連線。此外,由於建構函式接受資料庫 URL 作為引數,因此可以透過此提議的類服務多個 SqLite 資料庫(事實上,如果可以使用,還可以使用不同的 JDBC 提供程式服務完全不同的資料庫型別)。如果你仔細考慮一下,這應該會讓你想到,實際上我們最終需要的是一個通用的資料庫方法的抽象基類,我們可以從中繼承來提供特定於資料庫型別的具體類,例如,我們有一個名為 DbBaseClass 的抽象基類,我們可以從中派生 SqLiteDbClass、OracleDbClass、MySQlDbClass 等類。
你會注意到,現在只需要 java.sql.ResultSet 匯入到 main 中,因為資料庫邏輯將封裝在其他地方。最終,我們應該考慮將那個不整齊的 ResultSet 迴圈塊封裝為另一個類的特定方法,該方法專門用於處理查詢結果,以便將其方法提供給一個橋接資料庫邏輯的具體實現和資料返回方式的介面類等。但是,這在目前有點離題,因為我們現在真正感興趣的是讓我們的資料庫按照我們想要的方式執行。
main 方法預期存在(至少)三個公開可用的方法,以及(至少)一個接受 URL 作為引數的建構函式
- void execute(String)
- ResultSet executeQuery(String)
- void close()
它不可避免地還需要一些私有方法和欄位來滿足此封裝。讓我們從建構函式和它需要提供可行的資料庫類的一些明顯方法開始。
{imports}
public class DbClass {
public String sUrl; // for advertising and debug purposes
private String sDriverName = "org.sqlite.JDBC";
private String sDriver;
private Connection conn = null;
private Statement stmt = null;
public DbClass(String sDbUrl) {
sUrl = sDbUrl;
sDriverName = getDriverString(sDbUrl); // i.e. we will need a
// function to split the
// driver string from the
// passed URL
/*
* which in itself suggests we may provide a constructor overload
* which takes the full URL and the DriverName....
*/
setConnection();
}
private void setConnection() throws Exception {
try {
Class.forName(sDriverName);
} catch (Exception e) {
// connection failed.
System.out.println("DriverName: " + sDriver
+ " was not available");
System.err.println(e);
throw e;
}
// create a database connection
conn = DriverManager.getConnection(sUrl);
try {
stmt = conn.createStatement();
} catch (Exception e) {
try { conn.close(); } catch (Exception ignore) {}
conn = null;
}
}
// this method should undoubtedly be public as we'll want to call this
// to close connections externally to the class
public void closeConnection() {
if (stmt!=null) { try { stmt.close(); } catch (Exception ignore) {} }
if (conn!=null) { try { conn.close(); } catch (Exception ignore) {} }
}
// and we will definitely want to be able to call the following two
// functions externally since they expose the database
// behaviour which we are trying to access
public ResultSet executeQuery(String instruction) throws SQLException {
return stmt.executeQuery(instruction);
}
public void execute(String instruction) throws SQLException {
stmt.executeUpdate(instruction);
}
}
顯然,這是一個非常簡化的推測性資料庫類的實現,它實際上並不完全面向物件。但是,它確實代表了我們開始的最初 HelloDatabase.java 的一個重大進步。