数据库操作
要对数据表中的数据进行操作,首先需要建立与数据库的连接。JDBC API 中提供的各种类可对数据表中的数据进行查找、添加、修改、删除等操作。本节以 MySQL 数据库为例,讲解几种常见的数据库操作。
连接数据库
要访问数据库,首先需要加载数据库的驱动程序(只需要在第一次访问数据库时加载一次),然后每次访问数据时创建一个 Connection 对象,接着执行操作数据库的 SQL 语句,最后在完成数据库操作后销毁前面创建的 Connection 对象,释放与数据库的连接。
【例17.1】连接本地的MySQL 8.0数据库(实例位置:资源包\TM\sl\17\1)
创建 ConnectionUtil 类,在主方法中加载 MySQL 8.0 的驱动包,并连接本地 MySQL 8.0 数据库,如果可正常连接,则输出成功提示。
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
public class ConnectionUtil {
public static void main(String[] args) {
Connection con = null; // 声明数据库连接对象
try {
Class.forName("com.mysql.cj.jdbc.Driver");// 加载数据库驱动类
// 通过访问数据库的URL,获取数据库连接对象
con = DriverManager.getConnection(
"jdbc:mysql://127.0.0.1:3306/test?useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=Asia/Shanghai&zeroDateTimeBehavior=CONVERT_TO_NULL&allowPublicKeyRetrieval=true",
"root", "123456");
} catch (SQLException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
if (con != null) {// 如果数据库不为空
System.out.println("数据库连接成功!");
System.out.println(con);
}
}
}
运行结果如下:
数据库连接成功!
com.mysql.cj.jdbc.ConnectionImpl@5fdcaa40
|
向数据库中发送SQL语句
例17.1只是获取与数据库的连接,要执行 SQL 语句,还需要创建 Statement 类对象。通过例17.1创建的连接数据库对象 con 的 createStatement() 方法可获得 Statement 对象,其语法如下:
Statement stmt = con.createStatement();
处理查询结果集
有了 Statement 对象以后,可调用相应的方法实现对数据库的查询和修改,并将查询的结果集存储在 ResultSet 类的对象中。例如,执行 “select * from tb_stu” 语句,并保存查询的结果集,其语法如下:
ResultSet res = stmt.executeQuery("select * from tb_stu");
运行结果为返回一个 ResultSet 对象。ResultSet 对象一次只可以看到结果集中的一行数据,使用该类的 next() 方法可将光标从当前位置移向下一行。
顺序查询
ResultSet 类的 next() 方法的返回值是 boolean 类型的数据,当游标移动到最后一行之后会返回 false。下面的实例就是将数据表 tb_emp 中的全部信息显示在控制台上。
【例17.2】查询数据库中tb_stu表中的所有数据(实例位置:资源包\TM\sl\17\2)
将 “资源包\TM\sl\17\test.sql” 脚本文件导入 MySQL 8.0 数据库中,并在 test 库中查询 tb_stu 表,则可以看到如图17.3所示结果。
创建 JDBCDemo 类,在主方法中连接 MySQL 8.0 数据库,将 tb_stu 表中的所有数据都输出到控制台中。

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
public class JDBCDemo {
public static void main(String[] args) {
try {
Class.forName("com.mysql.cj.jdbc.Driver");// 加载数据库驱动类
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
try {
// 通过访问数据库的URL,获取数据库连接对象
Connection con = DriverManager.getConnection(
"jdbc:mysql://127.0.0.1:3306/test?useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=Asia/Shanghai&zeroDateTimeBehavior=CONVERT_TO_NULL&allowPublicKeyRetrieval=true",
"root", "123456");
Statement stmt = con.createStatement();
ResultSet res = stmt.executeQuery("select * from tb_stu");
while (res.next()) { // 如果当前语句不是最后一条,则进入循环
String id = res.getString("id"); // 获取列名是id的字段值
String name = res.getString("name"); // 获取列名是name的字段值
String sex = res.getString("sex"); // 获取列名是sex的字段值
String birthday = res.getString("birthday"); // 获取列名是birthday的字段值
System.out.print("编号:" + id); // 将列值输出
System.out.print(" 姓名:" + name);
System.out.print(" 性别:" + sex);
System.out.println(" 生日:" + birthday);
}
con.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
运行结果如下:
编号:1 姓名:张三 性别:男 生日:1998-02-06
编号:2 姓名:李四 性别:女 生日:1995-06-28
编号:3 姓名:王五 性别:女 生日:1999-11-23
编号:4 姓名:赵六 性别:男 生日:2000-05-30
模糊查询
SQL 语句中提供了 LIKE 操作符以用于模糊查询,可使用 “%” 来代替 0 个或多个字符,使用下画线 “_” 来代替一个字符。例如,在查询姓张的同学的信息时,可使用以下 SQL 语句:
select * from tb_stu where name like '张%'
【例17.3】找出所有姓张的同学(实例位置:资源包\TM\sl\17\3)
本例在例17.2的基础上进行修改,为查询语句添加 like 关键字,然后将姓张的同学的全部信息输出到控制台中。
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
public class JDBCDemo2 {
public static void main(String[] args) {
try {
Class.forName("com.mysql.cj.jdbc.Driver");// 加载数据库驱动类
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
try {
// 通过访问数据库的URL,获取数据库连接对象
Connection con = DriverManager.getConnection(
"jdbc:mysql://127.0.0.1:3306/test?useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=Asia/Shanghai&zeroDateTimeBehavior=CONVERT_TO_NULL&allowPublicKeyRetrieval=true",
"root", "123456");
Statement stmt = con.createStatement();
ResultSet res = stmt.executeQuery("select * from tb_stu where name like '张%'");
while (res.next()) { // 如果当前语句不是最后一条,则进入循环
String id = res.getString("id"); // 获取列名是id的字段值
String name = res.getString("name"); // 获取列名是name的字段值
String sex = res.getString("sex"); // 获取列名是sex的字段值
String birthday = res.getString("birthday"); // 获取列名是birthday的字段值
System.out.print("编号:" + id); // 将列值输出
System.out.print(" 姓名:" + name);
System.out.print(" 性别:" + sex);
System.out.println(" 生日:" + birthday);
}
con.close(); // 关闭数据库连接
} catch (SQLException e) {
e.printStackTrace();
}
}
}
运行结果如下:
编号:1 姓名:张三 性别:男 生日:1998-02-06
预处理语句
向数据库发送一个 SQL 语句,数据库中的 SQL 解释器负责把 SQL 语句生成为底层的内部命令,然后执行该命令,完成相关的数据操作。如果不断地向数据库中提交 SQL 语句,则肯定会增加数据库中 SQL 解释器的负担,影响执行的速度。
JDBC 可以通过 Connection 对象的 preparedStatement(String sql) 方法来对 SQL 语句进行预处理,生成数据库底层的内部命令,并将该命令封装在 PreparedStatement 对象中。通过调用该对象的相应方法,SQL 语句可执行底层数据库命令。也就是说,应用程序能针对连接的数据库,将 SQL 语句解释为数据库底层的内部命令,然后让数据库执行这个命令。这样,可以减轻数据库的负担,提高访问数据库的速度。
对 SQL 进行预处理时可以使用通配符 “?” 来代替任何的字段值。例如:
sql = con.prepareStatement("select * from tb_stu where id = ?");
在执行预处理语句前,必须用相应方法来设置通配符所表示的值。例如:
sql.setInt(1,16);
上述语句中的1表示从左向右的第1个通配符,16表示设置的通配符的值。将通配符的值设置为16后,功能等同于:
sql = con.prepareStatement("select * from tb_stu where id = 16");
书写两条语句看似麻烦了一些,但使用预处理语句可使应用程序动态地改变 SQL 语句中关于字段值条件的设定。
通过 setXXX() 方法为 SQL 语句中的参数赋值时,建议使用与参数匹配的方法,也可以使用 setObject() 方法为各种类型的参数赋值。例如: sql.setObject(2,'李丽'); |
【例17.4】找出编号为3的同学(实例位置:资源包\TM\sl\17\4)
本例在例17.2的基础上进行修改,使用预处理语句动态地查询编号为3的同学信息,并将该同学的全部信息输出到控制台中。
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
public class JDBCDemo3 {
public static void main(String[] args) {
try {
Class.forName("com.mysql.cj.jdbc.Driver");// 加载数据库驱动类
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
try {
// 通过访问数据库的URL,获取数据库连接对象
Connection con = DriverManager.getConnection(
"jdbc:mysql://127.0.0.1:3306/test?useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=Asia/Shanghai&zeroDateTimeBehavior=CONVERT_TO_NULL&allowPublicKeyRetrieval=true",
"root", "123456");
PreparedStatement ps = con.prepareStatement("select * from tb_stu where id = ?");
ps.setInt(1, 3); // 设置参数
ResultSet rs = ps.executeQuery(); // 执行预处理语句
// 如果当前记录不是结果集中的最后一行,则进入循环体
while (rs.next()) {
String id = rs.getString(1); // 获取结果集中第一列的值
String name = rs.getString("name"); // 获取name列的列值
String sex = rs.getString("sex"); // 获取sex列的列值
String birthday = rs.getString("birthday"); // 获取birthday列的列值
System.out.print("编号:" + id); // 输出信息
System.out.print(" 姓名:" + name);
System.out.print(" 性别:" + sex);
System.out.println(" 生日:" + birthday);
}
con.close(); // 关闭数据库连接
} catch (SQLException e) {
e.printStackTrace();
}
}
}
运行结果如下:
编号:3 姓名:王五 性别:女 生日:1999-11-23
添加修改删除记录
SQL 语句可以对数据执行添加、修改和删除操作。可通过 PreparedStatement 类的指定参数来动态地对数据表中原有数据进行修改操作,并通过 executeUpdate() 方法执行更新语句操作。
【例17.5】对学生表进行添加、修改和删除操作(实例位置:资源包\TM\sl\17\5)
创建 JDBCDemo4 类,在类中编写相应的方法,分别用来初始化数据库连接、关闭数据库连接、查询所有学生数据、添加新学生数据、修改指定编号的学生姓名和删除指定学生的全部数据。最后模拟以下场景。
-
添加新学生:姓名王富贵,男,生日1990-12-30,编号为 5。
-
将编号为 2 的学生姓名修改为 “李美丽”。
-
删除编号为 3 的学生。
具体代码如下:
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
public class JDBCDemo4 {
Connection con;// 声明数据库连接对象
public void initConnection() {// 初始化数据库连接
try {
Class.forName("com.mysql.cj.jdbc.Driver");// 加载数据库驱动类
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
try {
// 通过访问数据库的URL,获取数据库连接对象
con = DriverManager.getConnection(
"jdbc:mysql://127.0.0.1:3306/test?useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=Asia/Shanghai&zeroDateTimeBehavior=CONVERT_TO_NULL&allowPublicKeyRetrieval=true",
"root", "123456");
} catch (SQLException e) {
e.printStackTrace();
}
}
public void closeConnection() {// 关闭数据库连接
if (con != null) {
try {
con.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
public void showAllData() {// 显示所有学生数据
try {
Statement stmt = con.createStatement();
ResultSet rs = stmt.executeQuery("select * from tb_stu");
while (rs.next()) { // 如果当前语句不是最后一条,则进入循环
System.out.print("编号:" + rs.getString("id")); // 将列值输出
System.out.print(" 姓名:" + rs.getString("name"));
System.out.print(" 性别:" + rs.getString("sex"));
System.out.println(" 生日:" + rs.getString("birthday"));
}
} catch (SQLException e) {
e.printStackTrace();
}
}
public void add(int id, String name, String sex, String birthday) {// 添加新学生
try {
String sql = "insert into tb_stu values(?,?,?,?) ";
PreparedStatement ps = con.prepareStatement(sql);
ps.setInt(1, id); // 设置编号
ps.setString(2, name); // 设置名字
ps.setString(3, sex); // 设置性别
ps.setString(4, birthday); // 设置出生日期
ps.executeUpdate();
} catch (SQLException e) {
e.printStackTrace();
}
}
public void delete(int id) {// 删除指定ID的学生
try {
Statement stmt = con.createStatement();
stmt.executeUpdate("delete from tb_stu where id =" + id);
} catch (SQLException e) {
e.printStackTrace();
}
}
public void update(int id, String newName) {// 修改指定ID的学会姓名
try {
String sql = "update tb_stu set name = ? where id = ? ";
PreparedStatement ps = con.prepareStatement(sql);
ps.setString(1, newName); // 设置名字
ps.setInt(2, id); // 设置编号
ps.executeUpdate();
} catch (SQLException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
JDBCDemo4 demo = new JDBCDemo4();
demo.initConnection();
demo.showAllData();
System.out.println("---添加新同学---");
demo.add(5, "王富贵","男","1990-12-30");
demo.showAllData();
System.out.println("---修改编号为2的学生姓名---");
demo.update(2, "李美丽");
demo.showAllData();
System.out.println("---删除编号为3的学生---");
demo.delete(3);
demo.showAllData();
demo.closeConnection();
}
}
运行结果如下:
编号:1 姓名:张三 性别:男 生日:1998-02-06
编号:2 姓名:李四 性别:女 生日:1995-06-28
编号:3 姓名:王五 性别:女 生日:1999-11-23
编号:4 姓名:赵六 性别:男 生日:2000-05-30
---添加新同学---
编号:1 姓名:张三 性别:男 生日:1998-02-06
编号:2 姓名:李四 性别:女 生日:1995-06-28
编号:3 姓名:王五 性别:女 生日:1999-11-23
编号:4 姓名:赵六 性别:男 生日:2000-05-30
编号:5 姓名:王富贵 性别:男 生日:1990-12-30
---修改编号为2的学生姓名---
编号:1 姓名:张三 性别:男 生日:1998-02-06
编号:2 姓名:李美丽 性别:女 生日:1995-06-28
编号:3 姓名:王五 性别:女 生日:1999-11-23
编号:4 姓名:赵六 性别:男 生日:2000-05-30
编号:5 姓名:王富贵 性别:男 生日:1990-12-30
---删除编号为3的学生---
编号:1 姓名:张三 性别:男 生日:1998-02-06
编号:2 姓名:李美丽 性别:女 生日:1995-06-28
编号:4 姓名:赵六 性别:男 生日:2000-05-30
编号:5 姓名:王富贵 性别:男 生日:1990-12-30