
在当今的软件开发中,几乎所有应用程序都需要与数据库进行交互。无论是小型应用还是大型企业系统,数据的存储、检索和管理都是核心功能。JDBC(Java Database Connectivity)作为 Java 语言访问数据库的标准接口,为开发者提供了一种统一的方式来操作各种关系型数据库。
本章将详细介绍 JDBC 数据库编程的相关知识,从数据库基础知识到 JDBC API 的具体使用,再到实际应用案例,帮助读者掌握 Java 操作数据库的核心技能。

数据库系统(Database System)是由数据库、数据库管理系统(DBMS)、应用程序和数据库管理员(DBA)组成的系统。它的主要功能是存储、管理和检索数据,同时保证数据的安全性、完整性和一致性。
关系数据库是目前应用最广泛的数据库类型,它以表格(Table)的形式组织数据,表格之间通过关系(Relationship)建立联系。
关系数据库的主要特点是使用关系模型(二维表格模型)来组织数据,通过 SQL 语言进行操作。
SQL(Structured Query Language,结构化查询语言)是用于管理关系数据库的标准语言。它可以分为以下几类:
SELECTINSERT、UPDATE、DELETECREATE、ALTER、DROPGRANT、REVOKE常用 SQL 语句示例:
-- 创建表
CREATE TABLE students (
id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(50) NOT NULL,
age INT,
gender VARCHAR(10),
major VARCHAR(50)
);
-- 插入数据
INSERT INTO students (name, age, gender, major) VALUES ('张三', 20, '男', '计算机科学');
-- 查询数据
SELECT * FROM students WHERE age > 18;
-- 更新数据
UPDATE students SET age = 21 WHERE name = '张三';
-- 删除数据
DELETE FROM students WHERE id = 1;MySQL 是一种开源的关系型数据库管理系统,由于其开源免费、性能优良、易于使用等特点,被广泛应用于各种 Web 应用中。
apt-get install mysql-server(Ubuntu)安装完成后,可以通过命令行工具操作 MySQL:
登录 MySQL
mysql -u root -p输入密码后即可登录
常用命令
-- 显示所有数据库
SHOW DATABASES;
-- 创建数据库
CREATE DATABASE mydb;
-- 使用数据库
USE mydb;
-- 显示当前数据库中的所有表
SHOW TABLES;
-- 查看表结构
DESCRIBE students;
-- 退出MySQL
EXIT;Navicat 是一款功能强大的数据库管理工具,支持多种数据库,包括 MySQL、Oracle、SQL Server 等。使用图形界面操作数据库,比命令行更直观方便。
JDBC(Java Database Connectivity)是 Java 语言访问数据库的标准接口,它为 Java 开发者提供了一种统一的方式来访问各种关系型数据库。
JDBC 访问数据库的基本原理是通过驱动程序(Driver)与数据库进行通信。不同的数据库需要使用相应的驱动程序。
JDBC 访问数据库的流程如下:

JDBC API 主要包含以下核心接口和类:
这些接口和类都位于java.sql包中。

使用 JDBC 访问数据库通常遵循以下步骤:
在使用 JDBC 访问数据库之前,需要先加载相应的数据库驱动程序。
对于 MySQL 8.0 及以上版本,驱动类为com.mysql.cj.jdbc.Driver,可以通过以下方式加载:
// 加载MySQL驱动
Class.forName("com.mysql.cj.jdbc.Driver");注意:从 JDBC 4.0 开始,驱动程序可以自动加载,不需要显式调用
Class.forName()方法,但为了兼容性,通常还是会显式加载。
通过DriverManager.getConnection()方法建立与数据库的连接,需要提供数据库 URL、用户名和密码。
MySQL 的 URL 格式为:jdbc:mysql://主机名:端口号/数据库名?参数
// 数据库连接信息
String url = "jdbc:mysql://localhost:3306/mydb?useSSL=false&serverTimezone=UTC";
String username = "root";
String password = "123456";
// 建立连接
Connection conn = DriverManager.getConnection(url, username, password);通过Connection对象的方法创建语句对象,常用的有:
createStatement():创建Statement对象prepareStatement(String sql):创建PreparedStatement对象// 创建Statement对象
Statement stmt = conn.createStatement();
// 或者创建PreparedStatement对象
String sql = "SELECT * FROM students WHERE age > ?";
PreparedStatement pstmt = conn.prepareStatement(sql);ResultSet对象代表 SQL 查询的结果集,通过它可以获取查询到的数据。
常用方法:
next():移动到下一行,返回true表示有数据getXxx(String columnName):获取指定列名的 Xxx 类型数据getXxx(int columnIndex):获取指定列索引(从 1 开始)的 Xxx 类型数据// 执行查询
String sql = "SELECT id, name, age FROM students";
ResultSet rs = stmt.executeQuery(sql);
// 处理结果集
while (rs.next()) {
int id = rs.getInt("id");
String name = rs.getString("name");
int age = rs.getInt("age");
System.out.println("ID: " + id + ", 姓名: " + name + ", 年龄: " + age);
}数据库操作完成后,需要关闭相关对象,释放资源。关闭顺序与创建顺序相反:
ResultSetStatement或PreparedStatementConnection// 关闭资源
if (rs != null) {
try {
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (stmt != null) {
try {
stmt.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (conn != null) {
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}下面通过一个完整的示例来演示如何使用 JDBC 访问 MySQL 数据库。
首先,我们需要创建一个数据库和表来存储学生信息:
-- 创建数据库
CREATE DATABASE IF NOT EXISTS studentdb CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
-- 使用数据库
USE studentdb;
-- 创建学生表
CREATE TABLE IF NOT EXISTS students (
id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(50) NOT NULL,
age INT,
gender VARCHAR(10),
major VARCHAR(50)
);
-- 插入测试数据
INSERT INTO students (name, age, gender, major) VALUES
('张三', 20, '男', '计算机科学'),
('李四', 21, '女', '软件工程'),
('王五', 19, '男', '数据科学');下面是一个完整的 Java 程序,演示如何连接 MySQL 数据库,并执行查询、插入、更新和删除操作:
import java.sql.*;
/**
* JDBC访问MySQL数据库示例
*/
public class MySQLDemo {
// 数据库连接信息
private static final String URL = "jdbc:mysql://localhost:3306/studentdb?useSSL=false&serverTimezone=UTC";
private static final String USERNAME = "root";
private static final String PASSWORD = "123456"; // 请替换为你的密码
public static void main(String[] args) {
Connection conn = null;
try {
// 1. 加载驱动
Class.forName("com.mysql.cj.jdbc.Driver");
// 2. 建立连接
conn = DriverManager.getConnection(URL, USERNAME, PASSWORD);
System.out.println("数据库连接成功!");
// 3. 执行操作
// 查询所有学生
System.out.println("\n===== 所有学生 =====");
queryAllStudents(conn);
// 添加新学生
System.out.println("\n===== 添加新学生 =====");
addStudent(conn, "赵六", 22, "男", "人工智能");
queryAllStudents(conn);
// 更新学生信息
System.out.println("\n===== 更新学生信息 =====");
updateStudentAge(conn, 4, 23);
queryAllStudents(conn);
// 删除学生
System.out.println("\n===== 删除学生 =====");
deleteStudent(conn, 4);
queryAllStudents(conn);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
} finally {
// 4. 关闭连接
if (conn != null) {
try {
conn.close();
System.out.println("\n数据库连接已关闭!");
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
/**
* 查询所有学生
*/
public static void queryAllStudents(Connection conn) throws SQLException {
Statement stmt = null;
ResultSet rs = null;
try {
// 创建Statement对象
stmt = conn.createStatement();
// 执行查询
String sql = "SELECT id, name, age, gender, major FROM students";
rs = stmt.executeQuery(sql);
// 处理结果集
while (rs.next()) {
int id = rs.getInt("id");
String name = rs.getString("name");
int age = rs.getInt("age");
String gender = rs.getString("gender");
String major = rs.getString("major");
System.out.printf("ID: %d, 姓名: %s, 年龄: %d, 性别: %s, 专业: %s%n",
id, name, age, gender, major);
}
} finally {
// 关闭资源
if (rs != null) rs.close();
if (stmt != null) stmt.close();
}
}
/**
* 添加学生
*/
public static void addStudent(Connection conn, String name, int age, String gender, String major) throws SQLException {
Statement stmt = null;
try {
stmt = conn.createStatement();
String sql = String.format(
"INSERT INTO students (name, age, gender, major) VALUES ('%s', %d, '%s', '%s')",
name, age, gender, major
);
int rows = stmt.executeUpdate(sql);
System.out.println("添加了 " + rows + " 条记录");
} finally {
if (stmt != null) stmt.close();
}
}
/**
* 更新学生年龄
*/
public static void updateStudentAge(Connection conn, int id, int newAge) throws SQLException {
Statement stmt = null;
try {
stmt = conn.createStatement();
String sql = "UPDATE students SET age = " + newAge + " WHERE id = " + id;
int rows = stmt.executeUpdate(sql);
System.out.println("更新了 " + rows + " 条记录");
} finally {
if (stmt != null) stmt.close();
}
}
/**
* 删除学生
*/
public static void deleteStudent(Connection conn, int id) throws SQLException {
Statement stmt = null;
try {
stmt = conn.createStatement();
String sql = "DELETE FROM students WHERE id = " + id;
int rows = stmt.executeUpdate(sql);
System.out.println("删除了 " + rows + " 条记录");
} finally {
if (stmt != null) stmt.close();
}
}
}注意:运行此程序前,需要添加 MySQL JDBC 驱动。如果使用 Maven 项目,可以在 pom.xml 中添加以下依赖:
xml
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.28</version>
</dependency>如果是非 Maven 项目,需要下载 mysql-connector-java.jar 并添加到项目的类路径中。
PreparedStatement是Statement的子接口,它可以预编译 SQL 语句,提高执行效率,并且可以防止 SQL 注入攻击,是推荐使用的方式。
通过Connection.prepareStatement()方法创建PreparedStatement对象:
String sql = "SELECT * FROM students WHERE age > ?";
PreparedStatement pstmt = conn.prepareStatement(sql);?是参数占位符,将在执行前设置具体的值。
使用PreparedStatement的setXxx()方法设置参数,然后执行 SQL 语句:
import java.sql.*;
/**
* PreparedStatement使用示例
*/
public class PreparedStatementDemo {
private static final String URL = "jdbc:mysql://localhost:3306/studentdb?useSSL=false&serverTimezone=UTC";
private static final String USERNAME = "root";
private static final String PASSWORD = "123456";
public static void main(String[] args) {
Connection conn = null;
try {
// 加载驱动并建立连接
Class.forName("com.mysql.cj.jdbc.Driver");
conn = DriverManager.getConnection(URL, USERNAME, PASSWORD);
// 使用PreparedStatement查询年龄大于20的学生
System.out.println("===== 年龄大于20的学生 =====");
queryStudentsByAge(conn, 20);
// 使用PreparedStatement添加学生
System.out.println("\n===== 添加新学生 =====");
addStudent(conn, "孙七", 22, "女", "物联网工程");
// 使用PreparedStatement更新学生信息
System.out.println("\n===== 更新学生专业 =====");
updateStudentMajor(conn, 5, "智能科学与技术");
} catch (ClassNotFoundException | SQLException e) {
e.printStackTrace();
} finally {
// 关闭连接
if (conn != null) {
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
/**
* 查询年龄大于指定值的学生
*/
public static void queryStudentsByAge(Connection conn, int minAge) throws SQLException {
PreparedStatement pstmt = null;
ResultSet rs = null;
try {
// 创建PreparedStatement对象
String sql = "SELECT id, name, age, gender, major FROM students WHERE age > ?";
pstmt = conn.prepareStatement(sql);
// 设置参数(参数索引从1开始)
pstmt.setInt(1, minAge);
// 执行查询
rs = pstmt.executeQuery();
// 处理结果
while (rs.next()) {
int id = rs.getInt("id");
String name = rs.getString("name");
int age = rs.getInt("age");
String gender = rs.getString("gender");
String major = rs.getString("major");
System.out.printf("ID: %d, 姓名: %s, 年龄: %d, 性别: %s, 专业: %s%n",
id, name, age, gender, major);
}
} finally {
// 关闭资源
if (rs != null) rs.close();
if (pstmt != null) pstmt.close();
}
}
/**
* 添加学生
*/
public static void addStudent(Connection conn, String name, int age, String gender, String major) throws SQLException {
PreparedStatement pstmt = null;
try {
String sql = "INSERT INTO students (name, age, gender, major) VALUES (?, ?, ?, ?)";
pstmt = conn.prepareStatement(sql);
// 设置参数
pstmt.setString(1, name);
pstmt.setInt(2, age);
pstmt.setString(3, gender);
pstmt.setString(4, major);
// 执行更新
int rows = pstmt.executeUpdate();
System.out.println("添加了 " + rows + " 条记录");
} finally {
if (pstmt != null) pstmt.close();
}
}
/**
* 更新学生专业
*/
public static void updateStudentMajor(Connection conn, int id, String newMajor) throws SQLException {
PreparedStatement pstmt = null;
try {
String sql = "UPDATE students SET major = ? WHERE id = ?";
pstmt = conn.prepareStatement(sql);
// 设置参数
pstmt.setString(1, newMajor);
pstmt.setInt(2, id);
// 执行更新
int rows = pstmt.executeUpdate();
System.out.println("更新了 " + rows + " 条记录");
} finally {
if (pstmt != null) pstmt.close();
}
}
}PreparedStatement与Statement相比有以下优势:
DAO(Data Access Object,数据访问对象)设计模式用于将数据访问逻辑与业务逻辑分离,提供一种统一的方式来访问数据。
DAO 模式的主要组件:
下面是一个使用 DAO 模式操作学生信息的完整示例:
/**
* 学生实体类
*/
public class Student {
private int id;
private String name;
private int age;
private String gender;
private String major;
// 构造方法
public Student() {}
public Student(String name, int age, String gender, String major) {
this.name = name;
this.age = age;
this.gender = gender;
this.major = major;
}
public Student(int id, String name, int age, String gender, String major) {
this.id = id;
this.name = name;
this.age = age;
this.gender = gender;
this.major = major;
}
// getter和setter方法
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getGender() {
return gender;
}
public void setGender(String gender) {
this.gender = gender;
}
public String getMajor() {
return major;
}
public void setMajor(String major) {
this.major = major;
}
@Override
public String toString() {
return "Student{id=" + id + ", name='" + name + "', age=" + age +
", gender='" + gender + "', major='" + major + "'}";
}
}2.学生 DAO 接口
import java.util.List;
/**
* 学生DAO接口
*/
public interface StudentDAO {
// 添加学生
void addStudent(Student student) throws SQLException;
// 根据ID查询学生
Student getStudentById(int id) throws SQLException;
// 查询所有学生
List<Student> getAllStudents() throws SQLException;
// 更新学生信息
void updateStudent(Student student) throws SQLException;
// 删除学生
void deleteStudent(int id) throws SQLException;
}3.学生 DAO 实现类
import java.sql.*;
import java.util.ArrayList;
import java.util.List;
/**
* 学生DAO实现类
*/
public class StudentDAOImpl implements StudentDAO {
private Connection conn;
// 构造方法,接收数据库连接
public StudentDAOImpl(Connection conn) {
this.conn = conn;
}
@Override
public void addStudent(Student student) throws SQLException {
PreparedStatement pstmt = null;
try {
String sql = "INSERT INTO students (name, age, gender, major) VALUES (?, ?, ?, ?)";
pstmt = conn.prepareStatement(sql);
pstmt.setString(1, student.getName());
pstmt.setInt(2, student.getAge());
pstmt.setString(3, student.getGender());
pstmt.setString(4, student.getMajor());
pstmt.executeUpdate();
} finally {
if (pstmt != null) pstmt.close();
}
}
@Override
public Student getStudentById(int id) throws SQLException {
PreparedStatement pstmt = null;
ResultSet rs = null;
try {
String sql = "SELECT id, name, age, gender, major FROM students WHERE id = ?";
pstmt = conn.prepareStatement(sql);
pstmt.setInt(1, id);
rs = pstmt.executeQuery();
if (rs.next()) {
return new Student(
rs.getInt("id"),
rs.getString("name"),
rs.getInt("age"),
rs.getString("gender"),
rs.getString("major")
);
}
return null;
} finally {
if (rs != null) rs.close();
if (pstmt != null) pstmt.close();
}
}
@Override
public List<Student> getAllStudents() throws SQLException {
PreparedStatement pstmt = null;
ResultSet rs = null;
try {
String sql = "SELECT id, name, age, gender, major FROM students";
pstmt = conn.prepareStatement(sql);
rs = pstmt.executeQuery();
List<Student> students = new ArrayList<>();
while (rs.next()) {
Student student = new Student(
rs.getInt("id"),
rs.getString("name"),
rs.getInt("age"),
rs.getString("gender"),
rs.getString("major")
);
students.add(student);
}
return students;
} finally {
if (rs != null) rs.close();
if (pstmt != null) pstmt.close();
}
}
@Override
public void updateStudent(Student student) throws SQLException {
PreparedStatement pstmt = null;
try {
String sql = "UPDATE students SET name = ?, age = ?, gender = ?, major = ? WHERE id = ?";
pstmt = conn.prepareStatement(sql);
pstmt.setString(1, student.getName());
pstmt.setInt(2, student.getAge());
pstmt.setString(3, student.getGender());
pstmt.setString(4, student.getMajor());
pstmt.setInt(5, student.getId());
pstmt.executeUpdate();
} finally {
if (pstmt != null) pstmt.close();
}
}
@Override
public void deleteStudent(int id) throws SQLException {
PreparedStatement pstmt = null;
try {
String sql = "DELETE FROM students WHERE id = ?";
pstmt = conn.prepareStatement(sql);
pstmt.setInt(1, id);
pstmt.executeUpdate();
} finally {
if (pstmt != null) pstmt.close();
}
}
}4.DAO 工厂类
import java.sql.Connection;
/**
* DAO工厂类
*/
public class DAOFactory {
// 获取StudentDAO实例
public static StudentDAO getStudentDAO(Connection conn) {
return new StudentDAOImpl(conn);
}
}5.测试类
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.List;
/**
* DAO模式测试类
*/
public class DAODemo {
private static final String URL = "jdbc:mysql://localhost:3306/studentdb?useSSL=false&serverTimezone=UTC";
private static final String USERNAME = "root";
private static final String PASSWORD = "123456";
public static void main(String[] args) {
Connection conn = null;
try {
// 加载驱动并建立连接
Class.forName("com.mysql.cj.jdbc.Driver");
conn = DriverManager.getConnection(URL, USERNAME, PASSWORD);
// 获取StudentDAO实例
StudentDAO studentDAO = DAOFactory.getStudentDAO(conn);
// 添加学生
System.out.println("===== 添加学生 =====");
Student newStudent = new Student("周八", 21, "男", "自动化");
studentDAO.addStudent(newStudent);
System.out.println("添加学生成功");
// 查询所有学生
System.out.println("\n===== 所有学生 =====");
List<Student> students = studentDAO.getAllStudents();
for (Student s : students) {
System.out.println(s);
}
// 根据ID查询学生
System.out.println("\n===== 查询ID为1的学生 =====");
Student student = studentDAO.getStudentById(1);
System.out.println(student);
// 更新学生信息
System.out.println("\n===== 更新学生信息 =====");
if (student != null) {
student.setAge(22);
studentDAO.updateStudent(student);
System.out.println("更新后:" + studentDAO.getStudentById(1));
}
// 删除学生
System.out.println("\n===== 删除最后一个学生 =====");
if (!students.isEmpty()) {
int lastId = students.get(students.size() - 1).getId();
studentDAO.deleteStudent(lastId);
System.out.println("删除后所有学生:");
for (Student s : studentDAO.getAllStudents()) {
System.out.println(s);
}
}
} catch (ClassNotFoundException | SQLException e) {
e.printStackTrace();
} finally {
// 关闭连接
if (conn != null) {
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
}DAO 设计模式的优点:
默认情况下,ResultSet只能向前移动,并且是只读的。但通过设置Statement的参数,可以创建可滚动和可更新的ResultSet。
可滚动的ResultSet允许在结果集中自由移动,可以向前、向后,甚至直接跳到特定行。
创建可滚动的Statement需要指定两个参数:
ResultSet.TYPE_SCROLL_INSENSITIVE 或 ResultSet.TYPE_SCROLL_SENSITIVEResultSet.CONCUR_READ_ONLY(默认,只读)import java.sql.*;
/**
* 可滚动的ResultSet示例
*/
public class ScrollableResultSetDemo {
private static final String URL = "jdbc:mysql://localhost:3306/studentdb?useSSL=false&serverTimezone=UTC";
private static final String USERNAME = "root";
private static final String PASSWORD = "123456";
public static void main(String[] args) {
Connection conn = null;
Statement stmt = null;
ResultSet rs = null;
try {
// 加载驱动并建立连接
Class.forName("com.mysql.cj.jdbc.Driver");
conn = DriverManager.getConnection(URL, USERNAME, PASSWORD);
// 创建可滚动的Statement
// 参数1:ResultSet.TYPE_SCROLL_INSENSITIVE 表示可滚动且对数据库的更改不敏感
// 参数2:ResultSet.CONCUR_READ_ONLY 表示只读
stmt = conn.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);
// 执行查询
String sql = "SELECT id, name, age FROM students";
rs = stmt.executeQuery(sql);
System.out.println("===== 正向遍历 =====");
while (rs.next()) {
System.out.printf("ID: %d, 姓名: %s, 年龄: %d%n",
rs.getInt("id"), rs.getString("name"), rs.getInt("age"));
}
System.out.println("\n===== 反向遍历 =====");
while (rs.previous()) {
System.out.printf("ID: %d, 姓名: %s, 年龄: %d%n",
rs.getInt("id"), rs.getString("name"), rs.getInt("age"));
}
System.out.println("\n===== 移动到第三行 =====");
rs.absolute(3); // 移动到绝对位置
System.out.printf("ID: %d, 姓名: %s, 年龄: %d%n",
rs.getInt("id"), rs.getString("name"), rs.getInt("age"));
System.out.println("\n===== 移动到最后一行 =====");
rs.last();
System.out.printf("ID: %d, 姓名: %s, 年龄: %d%n",
rs.getInt("id"), rs.getString("name"), rs.getInt("age"));
System.out.println("\n===== 移动到第一行 =====");
rs.first();
System.out.printf("ID: %d, 姓名: %s, 年龄: %d%n",
rs.getInt("id"), rs.getString("name"), rs.getInt("age"));
System.out.println("\n===== 当前行号 =====");
System.out.println("当前行号: " + rs.getRow());
} catch (ClassNotFoundException | SQLException e) {
e.printStackTrace();
} finally {
// 关闭资源
try { if (rs != null) rs.close(); } catch (SQLException e) { e.printStackTrace(); }
try { if (stmt != null) stmt.close(); } catch (SQLException e) { e.printStackTrace(); }
try { if (conn != null) conn.close(); } catch (SQLException e) { e.printStackTrace(); }
}
}
}ResultSet的常用移动方法:
next():移动到下一行previous():移动到上一行first():移动到第一行last():移动到最后一行absolute(int row):移动到指定行(正数从开头计数,负数从结尾计数)relative(int rows):相对当前位置移动指定行数beforeFirst():移动到第一行之前afterLast():移动到最后一行之后getRow():获取当前行号可更新的ResultSet允许直接通过结果集修改数据库中的数据。
创建可更新的Statement需要指定两个参数:
ResultSet.TYPE_SCROLL_INSENSITIVEResultSet.CONCUR_UPDATABLEimport java.sql.*;
/**
* 可更新的ResultSet示例
*/
public class UpdatableResultSetDemo {
private static final String URL = "jdbc:mysql://localhost:3306/studentdb?useSSL=false&serverTimezone=UTC";
private static final String USERNAME = "root";
private static final String PASSWORD = "123456";
public static void main(String[] args) {
Connection conn = null;
Statement stmt = null;
ResultSet rs = null;
try {
// 加载驱动并建立连接
Class.forName("com.mysql.cj.jdbc.Driver");
conn = DriverManager.getConnection(URL, USERNAME, PASSWORD);
// 创建可更新的Statement
// 参数1:ResultSet.TYPE_SCROLL_INSENSITIVE 表示可滚动
// 参数2:ResultSet.CONCUR_UPDATABLE 表示可更新
stmt = conn.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_UPDATABLE);
// 查询数据
String sql = "SELECT id, name, age, major FROM students";
rs = stmt.executeQuery(sql);
System.out.println("===== 更新前 =====");
while (rs.next()) {
System.out.printf("ID: %d, 姓名: %s, 年龄: %d, 专业: %s%n",
rs.getInt("id"), rs.getString("name"), rs.getInt("age"), rs.getString("major"));
}
// 更新数据
System.out.println("\n===== 执行更新 =====");
// 更新特定行
rs.absolute(2); // 移动到第二行
rs.updateInt("age", 23); // 更新年龄
rs.updateRow(); // 提交更新
// 插入新行
rs.moveToInsertRow(); // 移动到插入行
rs.updateString("name", "吴九");
rs.updateInt("age", 20);
rs.updateString("gender", "男");
rs.updateString("major", "电子信息工程");
rs.insertRow(); // 插入新行
rs.moveToCurrentRow(); // 移动回原来的位置
// 删除行
rs.last(); // 移动到最后一行
int deleteId = rs.getInt("id");
rs.deleteRow(); // 删除当前行
System.out.println("删除了ID为 " + deleteId + " 的学生");
// 显示更新后的数据
System.out.println("\n===== 更新后 =====");
rs.beforeFirst(); // 移动到结果集开头
while (rs.next()) {
System.out.printf("ID: %d, 姓名: %s, 年龄: %d, 专业: %s%n",
rs.getInt("id"), rs.getString("name"), rs.getInt("age"), rs.getString("major"));
}
} catch (ClassNotFoundException | SQLException e) {
e.printStackTrace();
} finally {
// 关闭资源
try { if (rs != null) rs.close(); } catch (SQLException e) { e.printStackTrace(); }
try { if (stmt != null) stmt.close(); } catch (SQLException e) { e.printStackTrace(); }
try { if (conn != null) conn.close(); } catch (SQLException e) { e.printStackTrace(); }
}
}
}使用可更新的ResultSet修改数据的方法:
updateXxx()方法修改列值updateRow()提交更新moveToInsertRow()移动到插入行updateXxx()方法设置新行的列值insertRow()插入新行moveToCurrentRow()移动回原来的位置deleteRow()删除行注意:不是所有的查询都可以生成可更新的
ResultSet,通常需要满足以下条件:
SELECT *(虽然 MySQL 允许,但不推荐)本章主要介绍了 JDBC 数据库编程的相关知识,包括:
PreparedStatement的使用,它比Statement更安全、高效ResultSet的使用掌握 JDBC 数据库编程是 Java 开发的重要技能,它使 Java 应用程序能够与各种关系型数据库进行交互,实现数据的存储、查询、更新和删除等操作。
要求:使用 DAO 设计模式,使用PreparedStatement防止 SQL 注入。
要求:使用可更新的ResultSet实现部分功能,使用事务保证数据一致性。

以上练习的参考答案可以通过实际开发来完成,建议按照本章介绍的 DAO 模式进行设计,将数据访问逻辑与业务逻辑分离,提高代码的可维护性和可扩展性。
希望本章的内容能帮助你掌握 JDBC 数据库编程的核心技能,为后续的 Java 开发打下坚实的基础。如果有任何疑问或建议,欢迎在评论区留言讨论!