36、JDBC 入门:基础步骤、示例与实用工具

JDBC 入门:基础步骤、示例与实用工具

1. 使用 JDBC 的基本步骤

在 Java 开发中,JDBC(Java Database Connectivity)是用于与数据库进行交互的标准 API。使用 JDBC 进行数据库操作,通常需要遵循以下几个基本步骤:
1. 加载 JDBC 驱动
要使用 JDBC 连接数据库,首先需要加载相应的 JDBC 驱动。可以使用 Class.forName 方法,传入驱动的全限定类名来加载驱动。由于该方法可能会抛出 ClassNotFoundException 异常,因此需要将其放在 try/catch 块中。示例代码如下:

try {
    Class.forName("connect.microsoft.MicrosoftDriver");
    Class.forName("oracle.jdbc.driver.OracleDriver");
    Class.forName("com.sybase.jdbc.SybDriver");
} catch(ClassNotFoundException cnfe) {
    System.err.println("Error loading driver: " + cnfe);
}

大多数数据库厂商会为其数据库提供免费的 JDBC 驱动,同时也有许多第三方厂商为旧数据库提供驱动。可以访问 http://java.sun.com/products/jdbc/drivers.html 获取最新的驱动列表。很多驱动厂商还提供免费试用版本,方便在不付费的情况下学习 JDBC。需要注意的是,大多数 JDBC 驱动以 JAR 文件形式分发,因此要确保在 CLASSPATH 设置中包含 JAR 文件的路径。
2. 定义连接 URL
加载驱动后,需要指定数据库服务器的位置。数据库连接 URL 使用 jdbc: 协议,其中包含服务器主机、端口和数据库名称等信息。不同数据库的 URL 格式可能不同,具体格式可参考相应驱动的文档。以下是 Oracle 和 Sybase 数据库的示例:

String host = "dbhost.yourcompany.com";
String dbName = "someName";
int port = 1234;
String oracleURL = "jdbc:oracle:thin:@" + host + ":" + port + ":" + dbName;
String sybaseURL = "jdbc:sybase:Tds:" + host  + ":" + port + ":" + "?SERVICENAME=" + dbName;

如果从 applet 中使用 JDBC,由于浏览器为防止恶意 applet 绕过企业防火墙,会限制 applet 只能与加载它的服务器进行网络连接。因此,若要在 applet 中使用 JDBC,数据库服务器需与 HTTP 服务器位于同一台机器上,或者使用代理服务器将数据库请求重定向到实际服务器。
3. 建立连接
使用 DriverManager 类的 getConnection 方法,传入连接 URL、数据库用户名和密码,即可建立与数据库的实际网络连接。该方法会抛出 SQLException 异常,所以需要使用 try/catch 块进行异常处理。示例代码如下:

String username = "jay_debesee";
String password = "secret";
Connection connection = DriverManager.getConnection(oracleURL, username, password);

在建立连接后,还可以使用 Connection 类的 getMetaData 方法获取数据库的相关信息,如数据库名称、版本、JDBC 驱动名称和版本等。示例代码如下:

DatabaseMetaData dbMetaData = connection.getMetaData();
String productName = dbMetaData.getDatabaseProductName();
System.out.println("Database: " + productName);
String productVersion = dbMetaData.getDatabaseProductVersion();
System.out.println("Version: " + productVersion);

Connection 类还有其他一些有用的方法,如 prepareStatement (创建 PreparedStatement )、 prepareCall (创建 CallableStatement )、 rollback (回滚自上次提交以来的语句)、 commit (提交自上次提交以来的操作)、 close (关闭连接)和 isClosed (检查连接是否已超时或被显式关闭)等。
4. 创建 Statement 对象
Statement 对象用于向数据库发送 SQL 查询和命令。可以使用 Connection 对象的 createStatement 方法创建 Statement 对象。示例代码如下:

Statement statement = connection.createStatement();
  1. 执行查询
    使用 Statement 对象的 executeQuery 方法可以执行 SQL 查询,并返回一个 ResultSet 对象,该对象包含查询结果。示例代码如下:
String query = "SELECT col1, col2, col3 FROM sometable";
ResultSet resultSet = statement.executeQuery(query);

如果要修改数据库,可以使用 executeUpdate 方法,并传入包含 UPDATE INSERT DELETE 语句的字符串。 Statement 类的其他有用方法还包括 execute (执行任意命令)和 setQueryTimeout (设置等待结果的最大延迟)等。此外,还可以创建参数化查询,将值提供给预编译的固定格式查询。
6. 处理结果
处理查询结果的最简单方法是逐行处理,使用 ResultSet next 方法逐行遍历结果集。在每一行中,可以使用 ResultSet 提供的各种 getXxx 方法,根据列索引或列名获取不同 Java 类型的结果。例如,使用 getInt 获取整数值,使用 getString 获取字符串值等。需要注意的是,列索引从 1 开始,这遵循 SQL 约定,而不是像 Java 数组那样从 0 开始。示例代码如下:

while(resultSet.next()) {
    System.out.println(resultSet.getString(1) + " " +
                       resultSet.getString(2) + " " +
                       resultSet.getString(3));
}

ResultSet 类除了 getXxx next 方法外,还有其他有用的方法,如 findColumn (获取指定列名的索引)、 wasNull (检查上一次 getXxx 结果是否为 SQL NULL)和 getMetaData (获取 ResultSet 的元数据信息)等。 getMetaData 方法非常有用,它返回一个 ResultSetMetaData 对象,通过该对象可以动态获取结果集的列数、列名、列类型等信息。
7. 关闭连接
使用完数据库连接后,应该显式地关闭连接,以释放资源。可以使用 Connection 对象的 close 方法关闭连接。示例代码如下:

connection.close();

如果预计后续还会进行数据库操作,建议推迟关闭连接,因为打开连接的开销通常较大。实际上,重用现有连接是一种重要的优化策略。

下面是使用 JDBC 进行数据库操作的基本步骤流程图:

graph LR
    A[加载 JDBC 驱动] --> B[定义连接 URL]
    B --> C[建立连接]
    C --> D[创建 Statement 对象]
    D --> E[执行查询]
    E --> F[处理结果]
    F --> G[关闭连接]
2. 基本 JDBC 示例

为了更好地理解上述基本步骤,下面通过一个简单的示例来展示如何使用 JDBC 连接数据库并查询数据。示例中的 FruitTest 类可以连接到 Oracle 或 Sybase 数据库,并打印出 fruits 表中预定列的值。
FruitTest 类的代码如下:

package coreservlets;
import java.sql.*;

/** A JDBC example that connects to either an Oracle or
 *  a Sybase database and prints out the values of
 *  predetermined columns in the "fruits" table.
*/
public class FruitTest {
    /** Reads the hostname, database name, username, password,
     *  and vendor identifier from the command line. It
     *  uses the vendor identifier to determine which
     *  driver to load and how to format the URL. The
     *  driver, URL, username, host, and password are then
     *  passed to the showFruitTable method.
     */
    public static void main(String[] args) {
        if (args.length < 5) {
            printUsage();
            return;
        }
        String vendorName = args[4];
        int vendor = DriverUtilities.getVendor(vendorName);
        if (vendor == DriverUtilities.UNKNOWN) {
            printUsage();
            return;
        }
        String driver = DriverUtilities.getDriver(vendor);
        String host = args[0];
        String dbName = args[1];
        String url = DriverUtilities.makeURL(host, dbName, vendor);
        String username = args[2];
        String password = args[3];
        showFruitTable(driver, url, username, password);
    }

    /** Get the table and print all the values. */
    public static void showFruitTable(String driver,
                                      String url,
                                      String username,
                                      String password) {
        try {
            // Load database driver if not already loaded.
            Class.forName(driver);
            // Establish network connection to database.
            Connection connection =
                    DriverManager.getConnection(url, username, password);
            // Look up info about the database as a whole.
            DatabaseMetaData dbMetaData = connection.getMetaData();
            String productName =
                    dbMetaData.getDatabaseProductName();
            System.out.println("Database: " + productName);
            String productVersion =
                    dbMetaData.getDatabaseProductVersion();
            System.out.println("Version: " + productVersion + "\n");
            System.out.println("Comparing Apples and Oranges\n" +
                    "============================");
            Statement statement = connection.createStatement();
            String query = "SELECT * FROM fruits";
            // Send query to database and store results.
            ResultSet resultSet = statement.executeQuery(query);
            // Look up information about a particular table.
            ResultSetMetaData resultsMetaData =
                    resultSet.getMetaData();
            int columnCount = resultsMetaData.getColumnCount();
            // Column index starts at 1 (a la SQL) not 0 (a la Java).
            for(int i=1; i<columnCount+1; i++) {
                System.out.print(resultsMetaData.getColumnName(i) +
                        "  ");
            }
            System.out.println();
            // Print results.
            while(resultSet.next()) {
                // Quarter
                System.out.print("    " + resultSet.getInt(1));
                // Number of Apples
                System.out.print("     " + resultSet.getInt(2));
                // Apple Sales
                System.out.print("   $" + resultSet.getFloat(3));
                // Number of Oranges
                System.out.print("    " + resultSet.getInt(4));
                // Orange Sales
                System.out.print("    $" + resultSet.getFloat(5));
                // Top Salesman
                System.out.println("      " + resultSet.getString(6));
            }
        } catch(ClassNotFoundException cnfe) {
            System.err.println("Error loading driver: " + cnfe);
        } catch(SQLException sqle) {
            System.err.println("Error connecting: " + sqle);
        }
    }

    private static void printUsage() {
        System.out.println("Usage: FruitTest host dbName " +
                "username password oracle|sybase.");
    }
}

为了方便管理驱动和生成连接 URL,示例中使用了 DriverUtilities 类,该类的代码如下:

package coreservlets;

/** Some simple utilities for building Oracle and Sybase
 *  JDBC connections. This is <I>not</I> general-purpose
 *  code -- it is specific to my local setup.
*/
public class DriverUtilities {
    public static final int ORACLE = 1;
    public static final int SYBASE = 2;
    public static final int UNKNOWN = -1;

    /** Build a URL in the format needed by the
     *  Oracle and Sybase drivers I am using.
     */
    public static String makeURL(String host, String dbName,
                                 int vendor) {
        if (vendor == ORACLE) {
            return("jdbc:oracle:thin:@" + host + ":1521:" + dbName);
        } else if (vendor == SYBASE) {
            return("jdbc:sybase:Tds:" + host  + ":1521" +
                    "?SERVICENAME=" + dbName);
        } else {
            return(null);
        }
    }

    /** Get the fully qualified name of a driver. */
    public static String getDriver(int vendor) {
        if (vendor == ORACLE) {
            return("oracle.jdbc.driver.OracleDriver");
        } else if (vendor == SYBASE) {
            return("com.sybase.jdbc.SybDriver");
        } else {
            return(null);
        }
    }

    /** Map name to int value. */
    public static int getVendor(String vendorName) {
        if (vendorName.equalsIgnoreCase("oracle")) {
            return(ORACLE);
        } else if (vendorName.equalsIgnoreCase("sybase")) {
            return(SYBASE);
        } else {
            return(UNKNOWN);
        }
    }
}

运行 FruitTest 类时,需要传入主机名、数据库名、用户名、密码和数据库供应商标识符作为命令行参数。例如,连接到 Oracle 数据库的命令如下:

java coreservlets.FruitTest dbhost1.apl.jhu.edu PTE hall xxxx oracle

连接到 Sybase 数据库的命令如下:

java coreservlets.FruitTest dbhost2.apl.jhu.edu 605741 hall xxxx sybase

运行上述命令后,程序会输出数据库的名称、版本以及 fruits 表的查询结果。

以下是 FruitTest 类的执行流程表格:
| 步骤 | 操作 | 代码示例 |
| — | — | — |
| 1 | 检查命令行参数 | if (args.length < 5) { printUsage(); return; } |
| 2 | 获取数据库供应商标识符 | int vendor = DriverUtilities.getVendor(vendorName); |
| 3 | 获取驱动名称和连接 URL | String driver = DriverUtilities.getDriver(vendor); String url = DriverUtilities.makeURL(host, dbName, vendor); |
| 4 | 调用 showFruitTable 方法 | showFruitTable(driver, url, username, password); |
| 5 | 加载驱动 | Class.forName(driver); |
| 6 | 建立连接 | Connection connection = DriverManager.getConnection(url, username, password); |
| 7 | 获取数据库元数据 | DatabaseMetaData dbMetaData = connection.getMetaData(); |
| 8 | 创建 Statement 对象 | Statement statement = connection.createStatement(); |
| 9 | 执行查询 | ResultSet resultSet = statement.executeQuery(query); |
| 10 | 获取结果集元数据 | ResultSetMetaData resultsMetaData = resultSet.getMetaData(); |
| 11 | 打印列名 | for(int i=1; i<columnCount+1; i++) { System.out.print(resultsMetaData.getColumnName(i) + " "); } |
| 12 | 打印查询结果 | while(resultSet.next()) { ... } |
| 13 | 异常处理 | catch(ClassNotFoundException cnfe) { ... } catch(SQLException sqle) { ... } |

3. 一些 JDBC 实用工具

在许多应用程序中,并不需要逐行处理查询结果。例如,在 Servlet 和 JSP 页面中,通常会将数据库结果(将所有值视为字符串)进行格式化,并以 HTML 表格(见相关部分)、Excel 电子表格(见相关部分)的形式呈现给用户,或者将结果分散在页面中展示。在这种情况下,拥有能够检索并存储整个 ResultSet 以便后续显示的方法可以简化处理过程。

本节介绍两个类,它们提供了这种基本功能以及一些格式化、显示和表创建实用工具。核心类是 DatabaseUtilities ,它实现了四个常见任务的静态方法:

  1. getQueryResults
    此方法连接到数据库,执行查询,将所有行作为字符串数组检索出来,并将它们放入 DBResults 对象中(见相关代码)。该方法还会将数据库产品名称、数据库版本、所有列的名称以及 Connection 对象放入 DBResults 对象中。 getQueryResults 有两个版本:一个用于建立新连接,另一个用于使用现有连接。

  2. createTable
    给定表名、表示列格式的字符串以及表示行值的字符串数组,此方法连接到数据库,删除指定表的任何现有版本,使用指定格式发出 CREATE TABLE 命令,然后为每一行发送一系列 INSERT INTO 命令。同样,有两个版本:一个用于建立新连接,另一个用于使用现有连接。

  3. printTable
    给定表名,此方法连接到指定的数据库,检索所有行,并将它们打印到标准输出。它通过将表名转换为 SELECT * FROM tableName 形式的查询,并将其传递给 getQueryResults 来检索结果。

下面是使用这些实用工具创建 fruits 表的示例代码 FruitCreation 类:

package coreservlets;
import java.sql.*;

/** Creates a simple table named "fruits" in either
 *  an Oracle or a Sybase database.
*/
public class FruitCreation {
    public static void main(String[] args) {
        if (args.length < 5) {
            printUsage();
            return;
        }
        String vendorName = args[4];
        int vendor = DriverUtilities.getVendor(vendorName);
        if (vendor == DriverUtilities.UNKNOWN) {
            printUsage();
            return;
        }
        String driver = DriverUtilities.getDriver(vendor);
        String host = args[0];
        String dbName = args[1];
        String url =
                DriverUtilities.makeURL(host, dbName, vendor);
        String username = args[2];
        String password = args[3];
        String format =
                "(quarter int, " +
                        "apples int, applesales float, " +
                        "oranges int, orangesales float, " +
                        "topseller varchar(16))";
        String[] rows =
                { "(1, 32248, 3547.28, 18459, 3138.03, ’Maria’)",
                        "(2, 35009, 3850.99, 18722, 3182.74, ’Bob’)",
                        "(3, 39393, 4333.23, 18999, 3229.83, ’Joe’)",
                        "(4, 42001, 4620.11, 19333, 3286.61, ’Maria’)" };
        Connection connection =
                DatabaseUtilities.createTable(driver, url,
                        username, password,
                        "fruits", format, rows,
                        false);
        // Test to verify table was created properly. Reuse
        // old connection for efficiency.
        DatabaseUtilities.printTable(connection, "fruits",
                11, true);
    }

    private static void printUsage() {
        System.out.println("Usage: FruitCreation host dbName " +
                "username password oracle|sybase.");
    }
}

运行 FruitCreation 类时,同样需要传入主机名、数据库名、用户名、密码和数据库供应商标识符作为命令行参数。例如:

java coreservlets.FruitCreation dbhost1.apl.jhu.edu PTE hall xxxx oracle

以下是 FruitCreation 类的执行流程表格:
| 步骤 | 操作 | 代码示例 |
| — | — | — |
| 1 | 检查命令行参数 | if (args.length < 5) { printUsage(); return; } |
| 2 | 获取数据库供应商标识符 | int vendor = DriverUtilities.getVendor(vendorName); |
| 3 | 获取驱动名称和连接 URL | String driver = DriverUtilities.getDriver(vendor); String url = DriverUtilities.makeURL(host, dbName, vendor); |
| 4 | 调用 createTable 方法创建表 | Connection connection = DatabaseUtilities.createTable(driver, url, username, password, "fruits", format, rows, false); |
| 5 | 调用 printTable 方法验证表是否创建成功 | DatabaseUtilities.printTable(connection, "fruits", 11, true); |

下面是使用这些 JDBC 实用工具的整体流程图:

graph LR
    A[开始] --> B[检查参数]
    B --> C{参数是否足够}
    C -- 是 --> D[获取供应商信息]
    C -- 否 --> E[打印使用说明并退出]
    D --> F[获取驱动和 URL]
    F --> G{选择操作}
    G -- 创建表 --> H[调用 createTable]
    G -- 查询结果 --> I[调用 getQueryResults]
    G -- 打印表 --> J[调用 printTable]
    H --> K[验证表创建]
    I --> L[处理结果]
    J --> M[输出结果]
    K --> N[结束]
    L --> N
    M --> N

总结

通过上述内容,我们详细介绍了使用 JDBC 进行数据库操作的基本步骤,包括加载驱动、定义连接 URL、建立连接、创建 Statement 对象、执行查询、处理结果和关闭连接等。同时,通过 FruitTest 示例展示了如何使用这些步骤连接到不同的数据库并查询数据,以及使用 DriverUtilities 类来管理驱动和生成连接 URL。此外,还介绍了一些 JDBC 实用工具,如 DatabaseUtilities 类提供的 getQueryResults createTable printTable 方法,这些工具可以简化数据库操作的处理过程。

在实际应用中,我们可以根据具体需求选择合适的方法和工具,同时要注意异常处理和资源管理,以确保程序的稳定性和性能。例如,在使用完数据库连接后,要及时关闭连接,避免资源泄漏;在处理查询结果时,可以根据需要选择逐行处理或使用实用工具一次性处理整个结果集。

希望这些内容能够帮助你更好地理解和使用 JDBC 进行数据库操作。如果你有任何疑问或需要进一步的帮助,请随时留言。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值