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 的一个重大进步。