09_database_03_jdbc-2

第七十八章 JDBC基本使用方法

1. JDBC使用的基本流程

当Java应用程序使用JDBC接口访问数据库时,整个数据访问过程大致可分为以下几个步骤。

  1. 注册JDBC驱动程序。根据连接数据库的类型,开发人员需要选择相应的数据库驱动程序。
  2. 建立与数据库的连接。在建立连接时,用户可以选择多种用户鉴权(User Authentication)的方式建立连接。最常用的一种方式是使用用户名和密码进行用户鉴权。
  3. 在建立了与数据库的连接后,应用程序可以向数据库发送指令,查询或者修改数据。
  4. 处理完毕之后,应用程序需关闭数据库连接,释放资源。

2. JDBC核心概念

在上述的操作过程中,开发人员需要使用如下几个核心概念。

  1. java.sql.Driver类表示的是JDBC驱动程序的接口。当驱动程序加载成功之后,会向DriverManager完成注册。
  2. java.sql.DriverManager:当驱动成功加载之后,开发人员可以从DriverManager从创建Connection对象,建立与数据库的连接。DriverManager可以同时注册和管理多个驱动程序。当需要创建数据库连接对象时,DriverManager会一个一个地询问驱动程序,并最终创建出Connection对象。
  3. java.sql.Connection类表示的是一条与数据库的连接。应用程序可以在连接上向数据库发送"数据查询指令"或者"数据更新指令"。一个Connection对象只能表示一条数据库连接。在某一时刻,一条数据库连接只能连接一个数据库。但是,一个应用程序可以同时获得多条数据库连接。这些连接可以都是连接的同一个数据库,也可以连接不同的数据库。
  4. java.sql.Statement类表示的是发给数据库的语句(Statement)。这些语句可以查询、增加、删除、修改数据库中的数据。在Statement家族中有三种Statement类。java.sql.Statement类用于表示一条可执行的语句。java.sql.PreparedStatement则表示一条预编译的语句(Pre-compiled Statement)。因为该条语句已预编译,当需要反复多次执行时,使用PreparedStatement的性能比使用Statement的高。java.sql.CallableStatement表示调用数据库中存储过程(Stored Procedure)的语句。
  5. java.sql.ResultSet:当执行查询语句时,查询的结果由ResultSet对象表示。应用程序可以使用ResultSet对象逐行逐列获得查询结果。
  6. java.sql.SQLException:在与数据库的交互中,如果发生任何错误或者异常,则程序会抛出SQLException异常。例如:查询语句错误,数据库连接中断等。

3. 代码示例

我们将以连接PostgreSQL数据库为例,展示如何使用JDBC接口查询数据库。如果读者对其他数据库感兴趣,也可以根据我们的提示,将代码示例修改为相应的数据库应用程序。

如果使用Maven管理项目的话,需要在pom.xml中添加如下依赖关系。

<dependency>
    <groupId>org.postgresql</groupId>
    <artifactId>postgresql</artifactId>
    <version>42.2.18</version>
</dependency>

如果使用Gradle管理项目的话,需要在build.gradle中添加如下依赖关系。

repositories {
  mavenCentral()
}

dependencies {
  compile group: 'org.postgresql', name: 'postgresql', version: '42.2.18'
}

当开发人员使用MySQL数据库时,需将Maven和Gradle配置文件中的驱动程序改为mysql-connector-java。使用Oracle时,需改为ojdbc。

假设我们在本地数据库中有一张student的表,它的内容如下。student表中有三列数据:

  1. Name为字符串类型,表示学生姓名。
  2. Age为整数类型,表示学生年龄。
  3. Gender为字符串类型,表示学生性别。
NameAgeGender
Adam18Male
Cindy19Female

我们首先定义StudentBean类,用于表示学生。StudentBean中的成员变量与表中各列数据一一对应。

public class StudentBean {
    private String name = null;
    private Integer Age = null;
    private String gender = null;
}

在StudentDB类中,我们实现了fetchAll()方法获取所有学生的信息。首先,我们在第一步中加载PostgreSQL的驱动程序。如果使用MySQL或者Oracle数据库的话,需要将MySQL和Oracle数据库的驱动程序类名传入Class.forName()方法中。

第二步是创建Connection对象,与数据库建立连接。JDBC支持多种建立数据库连接的方式,我们在例子中使用用户名和密码的方法检查用户合法性。不同数据库有着不同的url格式,因此,开发人员需要根据相应的格式构建url字符串。

在创建出Connection对象之后,开发人员就可以通过这个Connection对象向数据库发送"指令"了。但是,需要注意的是,当使用完毕之后,开发人员需要调用close()方法关闭Connection对象。因为,如果不关闭该连接的话,会造成"连接泄漏(Connection Leak)"错误。当该错误积累到一定程度时,将无法再与数据库建立新的连接。因为,在数据库看来,它已创建了足够多的连接了。

第三步是创建Statement对象用于执行查询语句。JDBC不仅支持多种方式来执行查询语句,而且还支持增加(Insert)、删除(Delete)、修改(Update)等语句。我们将在后续章节中详细介绍这些内容。在本例中,我们通过调用executeQuery()方法查询student表中的所有数据。类似的,使用完毕后,开发人员需要关闭Statement对象。所以,我们使用try-with-resource语句来帮助开发人员自动完成关闭操作。

当查询操作完成后,executeQuery()方法会返回一个ResultSet对象,用来表示查询的结果。ResultSet对象实际上维护的是类似于表结构的数据。ResultSet对象内部还保存着一个"游标"(Cursor)。初始时,这个"游标"指向第一行之前的位置(The cursor is positioned before the first row)。当开发人员调用next()方法后,这个"游标"会向前移动一行。因此,在第一次调用next()方法之后,这个"游标"会指向第一行。再调用一次next()方法后,这个"游标"会指向第二行。以此类推。在这个过程中,如果这个"游标"还能向后移动的话,换句话说,如果该"游标"尚未指向最后一行的话,next()方法会返回true,表示该"游标"还可以向前移动。如果当这个"游标"到达最后一行后,next()方法会返回false。在此之后,开发人员不应再调用next()函数移动该"游标"。

当这个"游标"指向某一行时,开发人员可以使用get*()方法来获取该行某一列的数据。当数据是字符串时,应使用getString()方法。当数据是整数时,应使用getInt()。get*()可以以列名或者列序号的方式获取该列数据。列名为字符串类型;序列号为整数类型。列序号从1开始。更多get*()方法的使用方法可参见ResultSet类的开发文档。

根据上述的ResultSet的使用方法,我们使用了while循环来遍历每一列。当"游标"指向某一行时,我们获取了该行的Name, Age和Gender数据。并根据这些数据,创建StudentBean对象,添加到allStudents列表中。

在处理完所有查询的数据之后,我们直接返回allStudents列表。注意,Connection和Statement对象会被自动关闭。她们关闭的顺序与她们创建的顺序正好相反,这是由try-with-resource特性确保的。

public class StudentDB {
    public List<Student> fetchAll() {
        List<Student> allStudents = new ArrayList<Student>();

        try {
            // 第一步:加载数据库驱动程序
            Class.forName("org.postgresql.Driver");

            // 当使用MySQL数据库时,需使用
            // Class.forName("com.mysql.jdbc.Driver").newInstance();

            // 当使用Oracle数据库时,需使用
            // Class.forName("oracle.jdbc.driver.OracleDriver");
        } catch (Exception ex) {
            System.err.println("org.postgresql.Driver not found.");
            return null;
        }

        // 第二步:当使用MySQL数据库时,需使用
        // String url = "jdbc:mysql://localhost/dbname";
        // 当使用Oracle数据库时,需使用
        // String url = "jdbc:oracle:thin@myhost:dbname";
        String url = "jdbc:postgresql://localhost/dbname";
        String username = "littlewaterdrop";
        String password = "password";

        // 创建Connection对象,并使用try-with-resource语句在使用完毕后自动关闭Connection对象。
        try (Connection connection = DriverManager.getConnection(url, username, password)) {
            // 第三步:创建Statement对象,并使用try-with-resource语句在使用完毕后自动关闭Statement对象。
            try (Statement stmt = connection.createStatement()) {
                // 执行查询语句
                ResultSet result = stmt.executeQuery("select name, age, gender from student;");

                // 第四步:遍历所有返回的数据,将其添加在allStudents列表中
                while (result.next()) {
                    String name = result.getString("name");
                    Integer age = result.getInt("age");
                    String gender = result.getString("gender");
                    allStudents.add(new Student(name, age, gender));
                }
            }
        }

        // 第五步,返回获得的数据
        return allStudents;
    }
}

4. 小结

本章介绍了使用JDBC接口访问数据库的基本原理和流程。在该流程中,应用程序需依次加载驱动程序,建立数据库连接,创建Statement对象,执行查询语句并检查查询结果。在完成所有的操作之后,应用程序还需要关闭Statement对象和Connection对象。这些是使用JDBC接口的基本流程。我们将在后续的章节中详细的介绍数据操作的几种不同的方式。

上一章
下一章

注册用户登陆后可留言

Copyright  2019 Little Waterdrop, LLC. All Rights Reserved.