本 JDBC 教程将帮助您学习如何使用 JDBC(Java 数据库连接)API 进行基本的数据库操作(CRUD - 创建、检索、更新和删除)。这些 CRUD 操作相当于 SQL 语言中的 INSERT、SELECT、UPDATE 和 DELETE 语句。虽然目标数据库系统是 MySQL,但同样的技术也可以应用于其他数据库系统,因为使用的查询语法是所有关系数据库系统都支持的标准 SQL。
我们将通过编写代码来管理名为SampleDB的 MySQL 数据库中的表Users的记录,来学习如何插入、查询、更新和删除数据库记录。
表中的内容:
1.先决条件
首先,请确保您的计算机上安装了以下软件:
- JDK(下载 JDK 7)。
- MySQL(下载 MySQL Community Server 5.6.12)。您可能还想下载 MySQL Workbench - 一个用于处理 MySQL 数据库的图形工具。
- MySQL 的 JDBC 驱动程序(下载 MySQL Connector/J 5.1.25)。提取 zip 存档并将mysql-connector-java-VERSION-bin.jar文件放入类路径(与 Java 源文件位于同一文件夹中)。
2. 创建一个示例 MySQL 数据库
让我们创建一个名为SampleDB的 MySQL 数据库,其中包含一个表Users,其结构如下:
在 MySQL Workbench 中执行以下 SQL 脚本:
1
2
3
4
5
6
7
8
9
10
11
12
|
create database SampleDB;
use SampleDB;
CREATE TABLE `users` (
`user_id` int(11) NOT NULL AUTO_INCREMENT,
`username` varchar(45) NOT NULL,
`password` varchar(45) NOT NULL,
`fullname` varchar(45) NOT NULL,
`email` varchar(45) NOT NULL,
PRIMARY KEY (`user_id`)
);
|
或者,如果您使用的是MySQL 命令行客户端程序,请将上述脚本保存到一个文件中,例如SQLScript.sql并执行以下命令:
源路径\To\The\Script\File\SQLScript.sql
这是在MySQL 命令行客户端程序中执行上述脚本时截取的示例屏幕截图:
3.了解主要的JDBC接口和类
让我们概述一下我们通常使用的 JDBC 的主要接口和类。它们都在java.sql包下可用:
- DriverManager:该类用于为特定的数据库类型(例如本教程中的 MySQL)注册驱动程序,并通过其getConnection()方法与服务器建立数据库连接。
- Connection:此接口表示已建立的数据库连接(会话),我们可以从中创建语句来执行查询和检索结果、获取有关数据库的元数据、关闭连接等。
- Statement和PreparedStatement:这些接口分别用于执行静态 SQL 查询和参数化 SQL 查询。Statement是PreparedStatement接口。他们常用的方法有:
-
- boolean execute(String sql) : 执行一般 SQL 语句。如果查询返回ResultSet则返回true如果查询返回更新计数或不返回任何内容false此方法只能与语句。
- int executeUpdate(String sql):执行 INSERT、UPDATE 或 DELETE 语句并返回指示受影响行数的更新帐户(例如,插入 1 行,或更新 2 行,或受影响 0 行)。
- ResultSet executeQuery(String sql):执行 SELECT 语句并返回一个ResultSet对象,该对象包含查询返回的结果。
准备好的语句是包含占位符(形式为问号?)的语句,动态值将在运行时设置。例如:
SELECT * from Users WHERE user_id=?
这里user_id的值由问号参数化,并将由PreparedStatement接口中的setXXX()方法之一设置,例如setInt(int index, int value)。
- ResultSet:包含由 SELECT 查询返回的表数据。使用该对象通过next()方法迭代结果集中的行,并使用getXXX()方法(例如getString()、 getInt()、 getFloat()等)获取当前行中列的值。列值可以通过索引号(从 1 开始)或列名来检索。
- SQLException:这个检查异常被声明为由上述所有方法抛出,所以我们必须在调用上述类的方法时显式地捕获这个异常。
4. 连接数据库
假设 MySQL 数据库服务器正在侦听localhost的默认端口3306。以下代码片段通过用户root和密码secret连接到数据库名称SampleDB:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
String dbURL = "jdbc:mysql://localhost:3306/sampledb" ;
String username = "root" ;
String password = "secret" ;
try {
Connection conn = DriverManager.getConnection(dbURL, username, password);
if (conn != null ) {
System.out.println( "Connected" );
}
} catch (SQLException ex) {
ex.printStackTrace();
}
|
建立连接后,我们就有了一个Connection对象,可用于创建语句以执行 SQL 查询。在上面的代码中,我们必须在完成数据库操作后显式关闭连接:
1
|
conn.close();
|
但是,从 Java 7 开始,我们可以利用try -with-resources 语句自动关闭连接,如以下代码片段所示:
1
2
3
4
5
6
7
|
try (Connection conn = DriverManager.getConnection(dbURL, username, password)) {
// code to execute SQL queries goes here...
} catch (SQLException ex) {
ex.printStackTrace();
}
|
如果您使用的是 Java 7 或更高版本,则建议使用此方法。本教程中的示例程序都使用这个try-with-resources语句来建立数据库连接。
注意:有关连接 MySQL 数据库的详细信息,请参阅文章:通过 JDBC 连接 MySQL 数据库。
5. JDBC执行INSERT语句示例
让我们编写代码以将新记录插入到表用户中,详细信息如下:
- 用户名:账单
- 密码:secretpass
- 全名:比尔盖茨
- 电子邮件:bill.gates@microsoft.com
这是代码片段:
1
2
3
4
5
6
7
8
9
10
11
12
|
String sql = "INSERT INTO Users (username, password, fullname, email) VALUES (?, ?, ?, ?)" ;
PreparedStatement statement = conn.prepareStatement(sql);
statement.setString( 1 , "bill" );
statement.setString( 2 , "secretpass" );
statement.setString( 3 , "Bill Gates" );
statement.setString( 4 , "bill.gates@microsoft.com" );
int rowsInserted = statement.executeUpdate();
if (rowsInserted > 0 ) {
System.out.println( "A new user was inserted successfully!" );
}
|
在这段代码中,我们创建了一个参数化的 SQL INSERT 语句,并从Connection对象创建了一个PreparedStatement 。为了设置 INSERT 语句中的参数值,我们使用PreparedStatement的setString()方法,因为表Users中的所有这些列都是 VARCHAR 类型,在 Java 中被转换为 String 类型。请注意,参数索引是基于 1 的(与 Java 数组中基于 0 的索引不同)。
PreparedStatement接口提供了与每种数据类型对应的各种setXXX ()方法,例如:
- setBoolean(int parameterIndex, boolean x)
- setDate(int parameterIndex, 日期 x)
- setFloat(int parameterIndex, float x)
- …
等等。使用哪种方法取决于数据库表中对应列的类型。
最后我们调用PreparedStatement的executeUpdate()方法来执行 INSERT 语句。此方法返回一个更新计数,指示表中有多少行受查询影响,因此检查此返回值对于确保查询成功执行是必要的。在这种情况下,executeUpdate()方法应返回 1 以指示插入了一条记录。
6. JDBC执行SELECT语句示例
以下代码片段查询用户表中的所有记录并打印出每条记录的详细信息:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
String sql = "SELECT * FROM Users" ;
Statement statement = conn.createStatement();
ResultSet result = statement.executeQuery(sql);
int count = 0 ;
while (result.next()){
String name = result.getString( 2 );
String pass = result.getString( 3 );
String fullname = result.getString( "fullname" );
String email = result.getString( "email" );
String output = "User #%d: %s - %s - %s - %s" ;
System.out.println(String.format(output, ++count, name, pass, fullname, email));
}
|
输出:
用户 #1:bill - secretpass - Bill Gates - bill.gates@microsoft.com
因为这里的 SQL SELECT 查询是静态的,所以我们只需从连接中创建一个Statement对象。while 循环通过重复检查ResultSet的next()方法的返回值来迭代结果集中包含的行。next()方法在结果集中向前移动光标以检查是否有任何剩余记录。对于每次迭代,结果集都包含当前行的数据,我们使用ResultSet的getXXX(column index/column name)方法来检索当前行中特定列的值,例如这个语句:
1
|
String name = result.getString( 2 );
|
检索当前行中第二列的值,即用户名字段。该值被转换为字符串,因为我们知道用户名字段是基于前面提到的数据库模式的 VARCHAR 类型。请记住,这里的列索引是从 1 开始的,第一列将在索引 1 处,第二列在索引 2 处,依此类推。如果您不确定或不确切知道列的索引,那么传递列名会很有用:
1
|
String fullname = result.getString( "fullname" );
|
对于其他数据类型,ResultSet提供了适当的 getter 方法:
- 获取字符串()
- 有色()
- 获取浮动()
- 获取日期()
- 获取时间戳()
- …
提示:按列索引访问列的值将提供比列名更快的性能。
7. JDBC执行UPDATE语句示例
下面的代码片段将更新我们之前插入的“Bill Gates”的记录:
1
2
3
4
5
6
7
8
9
10
11
12
|
String sql = "UPDATE Users SET password=?, fullname=?, email=? WHERE username=?" ;
PreparedStatement statement = conn.prepareStatement(sql);
statement.setString( 1 , "123456789" );
statement.setString( 2 , "William Henry Bill Gates" );
statement.setString( 3 , "bill.gates@microsoft.com" );
statement.setString( 4 , "bill" );
int rowsUpdated = statement.executeUpdate();
if (rowsUpdated > 0 ) {
System.out.println( "An existing user was updated successfully!" );
}
|
这段代码看起来与上面的 INSERT 代码非常相似,只是查询类型是 UPDATE。
8. JDBC执行DELETE语句示例
以下代码片段将删除用户名字段包含“bill”的记录:
1
2
3
4
5
6
7
8
9
|
String sql = "DELETE FROM Users WHERE username=?" ;
PreparedStatement statement = conn.prepareStatement(sql);
statement.setString( 1 , "bill" );
int rowsDeleted = statement.executeUpdate();
if (rowsDeleted > 0 ) {
System.out.println( "A user was deleted successfully!" );
}
|
到目前为止,我们已经通过一些示例演示了如何使用 JDBC API 来执行 SQL INSERT、SELECT、UPDATE 和 DELETE 语句。要记住的关键点是:
- 使用语句进行静态 SQL 查询。
- 使用PreparedStatement进行参数化 SQL 查询并使用setXXX()方法设置参数值。
- 使用execute()方法执行一般查询。
- 使用executeUpdate()方法执行 INSERT、UPDATE 或 DELETE 查询
- 使用executeQuery()方法执行 SELECT 查询。
- 使用ResultSet迭代从 SELECT 查询返回的行,使用其next()方法前进到结果集中的下一行,并使用getXXX()方法检索列的值。
您可以在附件部分下载每种查询类型的示例演示程序的源代码。
注意:如果您使用 Spring 框架访问关系数据库,请考虑使用Spring JdbcTemplate,它可以简化和减少您需要编写的代码。
JDBC API 参考: