Java JDBC 入门实战:工具类 + 增删改查 + 事务(附完整示例代码)
·
一、前言
本文基于个人练习项目,演示如何使用 JDBC 连接 MySQL,完成:
- 封装连接与关闭资源的 工具类(
JdbcUtil) - 查询(
JdbcTest) - 增删改(
JdbcInsert/JdbcUpdate/JdbcDelete) - 事务转账示例(
JdbcTransaction,含PreparedStatement)
适合刚学完 JDBC 的同学对照运行与理解。
二、环境准备
- JDK:建议 JDK 8 及以上
- MySQL:本地安装并启动服务
- 数据库与驱动
- 示例中连接库名:
day16(可在JdbcUtil中修改) - 需自行准备表
t_user(字段含id, username, password, email等,与下面 SQL 一致即可) - 引入 MySQL JDBC 驱动 jar(如
mysql-connector-java),并加入 classpath
- 示例中连接库名:
- 驱动类名说明(重要)
- 示例使用:
com.mysql.jdbc.Driver(偏老版本写法) - 若使用 MySQL 8+ 官方驱动,建议改为:
com.mysql.cj.jdbc.Driver,URL 中常加:?serverTimezone=Asia/Shanghai&useSSL=false等参数,避免时区与 SSL 报错
- 示例使用:
三、项目中的类说明
| 类名 | 作用 |
|---|---|
JdbcUtil |
加载驱动、获取连接、统一关闭资源 |
JdbcTest |
SELECT 查询 t_user |
JdbcInsert |
INSERT 插入用户 |
JdbcUpdate |
UPDATE 更新邮箱 |
JdbcDelete |
DELETE 按 id 删除 |
JdbcTransaction |
关闭自动提交、commit / rollback 演示转账 |
四、工具类:JdbcUtil
职责:集中配置、加载驱动、获取 Connection、关闭 ResultSet / Statement / Connection(避免每个类里重复写一堆 close)。
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
/**
* JDBC工具类
* 提供数据库连接获取和资源关闭的通用方法
*/
public class JdbcUtil {
// 数据库配置信息
private static final String DRIVER = "com.mysql.jdbc.Driver";
private static final String URL = "jdbc:mysql://localhost:3306/day16";
private static final String USER = "root";
private static final String PASSWORD = "123456";
// 静态代码块,在类加载时执行一次
static {
try {
Class.forName(DRIVER);
System.out.println("驱动加载成功!");
} catch (Exception e) {
System.err.println("驱动加载失败!");
e.printStackTrace();
}
}
/**
* 获取数据库连接
* @return Connection对象
* @throws Exception 数据库连接异常
*/
public static Connection getConnection() throws Exception {
return DriverManager.getConnection(URL, USER, PASSWORD);
}
/**
* 关闭数据库资源
* @param resultSet 结果集
* @param statement SQL语句执行器
* @param connection 数据库连接
*/
public static void close(ResultSet resultSet, Statement statement, Connection connection) {
// 关闭ResultSet
if (resultSet != null) {
try {
resultSet.close();
} catch (Exception e) {
e.printStackTrace();
}
}
// 关闭Statement
if (statement != null) {
try {
statement.close();
} catch (Exception e) {
e.printStackTrace();
}
}
// 关闭Connection
if (connection != null) {
try {
connection.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
/**
* 关闭数据库资源(重载方法,用于增删改操作)
* @param statement SQL语句执行器
* @param connection 数据库连接
*/
public static void close(Statement statement, Connection connection) {
close(null, statement, connection);
}
}
要点简述:
static 块里 Class.forName:加载驱动(部分新版本 JDBC 可省略,但写上更直观)。
getConnection():真正建立连接。
close(...):finally 里调用,先关 ResultSet,再 Statement,最后 Connection,顺序符合常见规范。
五、查询:JdbcTest
使用 Statement.executeQuery 执行 SELECT,用 while (resultSet.next()) 遍历结果。
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.Statement;
public class JdbcTest {
public static void main(String[] args) {
Connection connection = null;
Statement statement = null;
ResultSet resultSet = null;
try {
// 获取数据库连接
connection = JdbcUtil.getConnection();
System.out.println("数据库连接成功!");
// 创建Statement
statement = connection.createStatement();
// 执行查询
String sql = "select * from t_user";
resultSet = statement.executeQuery(sql);
// 处理结果集
while (resultSet.next()) {
int id = resultSet.getInt("id");
String username = resultSet.getString("username");
String pwd = resultSet.getString("password");
String email = resultSet.getString("email");
System.out.println("ID: " + id + ", Username: " + username + ", Password: " + pwd + ", Email: " + email);
}
} catch (Exception e) {
System.err.println("发生错误:");
e.printStackTrace();
} finally {
// 关闭资源
JdbcUtil.close(resultSet, statement, connection);
}
}
}
六、插入:JdbcInsert
增删改使用 Statement.executeUpdate,返回 受影响行数。
import java.sql.Connection;
import java.sql.Statement;
public class JdbcInsert {
public static void main(String[] args) {
Connection connection = null;
Statement statement = null;
try {
// 获取数据库连接
connection = JdbcUtil.getConnection();
System.out.println("数据库连接成功!");
// 创建Statement
statement = connection.createStatement();
// 执行插入操作
String sql = "INSERT INTO t_user (username, password, email) VALUES ('test_user2', 'test456', 'test2@example.com')";
int rows = statement.executeUpdate(sql);
System.out.println("插入成功!影响了 " + rows + " 行数据");
} catch (Exception e) {
System.err.println("发生错误:");
e.printStackTrace();
} finally {
// 关闭资源
JdbcUtil.close(statement, connection);
}
}
}
七、更新:JdbcUpdate
import java.sql.Connection;
import java.sql.Statement;
public class JdbcUpdate {
public static void main(String[] args) {
Connection connection = null;
Statement statement = null;
try {
// 获取数据库连接
connection = JdbcUtil.getConnection();
System.out.println("数据库连接成功!");
// 创建Statement
statement = connection.createStatement();
// 执行更新操作 - 将id为2的用户邮箱修改
String sql = "UPDATE t_user SET email = 'newemail@example.com' WHERE id = 2";
int rows = statement.executeUpdate(sql);
System.out.println("更新成功!影响了 " + rows + " 行数据");
} catch (Exception e) {
System.err.println("发生错误:");
e.printStackTrace();
} finally {
// 关闭资源
JdbcUtil.close(statement, connection);
}
}
}
八、删除:JdbcDelete
import java.sql.Connection;
import java.sql.Statement;
public class JdbcDelete {
public static void main(String[] args) {
Connection connection = null;
Statement statement = null;
try {
// 获取数据库连接
connection = JdbcUtil.getConnection();
System.out.println("数据库连接成功!");
// 创建Statement
statement = connection.createStatement();
// 执行删除操作 - 删除id为1的用户
String sql = "DELETE FROM t_user WHERE id = 1";
int rows = statement.executeUpdate(sql);
System.out.println("删除成功!影响了 " + rows + " 行数据");
} catch (Exception e) {
System.err.println("发生错误:");
e.printStackTrace();
} finally {
// 关闭资源
JdbcUtil.close(statement, connection);
}
}
}
小结:executeQuery 用于查询返回 ResultSet;executeUpdate 用于 INSERT/UPDATE/DELETE。生产环境更推荐 PreparedStatement 防 SQL 注入,事务示例里已用到。
九、事务:JdbcTransaction
9.1 什么是事务?
多条 SQL 组成一个业务单元:要么全部成功提交,要么出错则全部回滚,避免出现「扣款成功、入账失败」导致数据不一致。
事务常见特性 ACID:
A 原子性:要么全成,要么全败
C 一致性:数据约束与业务规则不被破坏
I 隔离性:并发事务之间相互隔离(程度与隔离级别有关)
D 持久性:提交后数据应持久保存
9.2 JDBC 里要记住的三行
connection.setAutoCommit(false); // 关闭自动提交 = 手动控制事务
connection.commit(); // 全部成功则提交
connection.rollback(); // 异常则回滚
9.3 建表与测试数据(transaction_test.sql)
在 MySQL 中执行(与项目中 transaction_test.sql 一致):
-- JDBC事务演示 - 创建账户表和测试数据
-- 创建账户表
CREATE TABLE IF NOT EXISTS t_account (
id INT PRIMARY KEY AUTO_INCREMENT,
username VARCHAR(50) NOT NULL,
balance DECIMAL(10, 2) DEFAULT 0.00,
create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
-- 插入测试数据(如果表为空)
INSERT INTO t_account (username, balance) VALUES
('张三', 5000.00),
('李四', 3000.00),
('王五', 8000.00)
ON DUPLICATE KEY UPDATE username=username;
-- 查询初始数据
SELECT * FROM t_account;
9.4 转账示例代码(JdbcTransaction)
下面程序演示:正常转账 与 余额不足触发回滚。
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
/**
* JDBC事务操作演示 - 简化版
*
* 什么是事务?
* 事务就是一系列操作,要么全部成功,要么全部失败。
*
* 举个例子:
* 张三给李四转账100元
* - 步骤1:张三的账户减少100元
* - 步骤2:李四的账户增加100元
*
* 如果步骤1成功了,但步骤2失败了怎么办?
* 如果没有事务,张三的钱就消失了!
* 有了事务,如果任何一步失败,所有操作都会撤销(回滚)。
*/
public class JdbcTransaction {
public static void main(String[] args) {
System.out.println("=== 开始测试事务 ===\n");
// 先查看初始余额
System.out.println("【第1步】查看初始余额:");
showAllAccounts();
// 测试1:正常转账
System.out.println("\n【第2步】测试正常转账:张三(1号) -> 李四(2号) 转500元");
System.out.println("----------------------------------------");
boolean success1 = transferMoney(1, 2, 500.0);
if (success1) {
System.out.println("结果:✓ 转账成功!\n");
} else {
System.out.println("结果:✗ 转账失败!\n");
}
// 测试2:余额不足
System.out.println("【第3步】测试余额不足:张三(1号) -> 李四(2号) 转999999元");
System.out.println("----------------------------------------");
boolean success2 = transferMoney(1, 2, 999999.0);
if (success2) {
System.out.println("结果:✓ 转账成功!\n");
} else {
System.out.println("结果:✗ 转账失败(已自动撤销)\n");
}
// 最后查看最终余额
System.out.println("【第4步】查看最终余额:");
showAllAccounts();
System.out.println("\n=== 测试结束 ===");
}
/**
* 转账方法
* @param fromId 转出账户ID(谁的钱要减少)
* @param toId 转入账户ID(谁的钱要增加)
* @param amount 转账金额
* @return 是否成功
*/
public static boolean transferMoney(int fromId, int toId, double amount) {
Connection connection = null;
PreparedStatement pstmtFrom = null; // 用于执行转出操作
PreparedStatement pstmtTo = null; // 用于执行转入操作
ResultSet resultSet = null;
try {
// ========== 第一步:连接数据库 ==========
connection = JdbcUtil.getConnection();
System.out.println("1. 数据库连接成功");
// ========== 第二步:开启事务 ==========
// 默认情况下,每执行一条SQL就会自动保存(自动提交)
// 我们需要关闭自动提交,这样才能控制什么时候保存
connection.setAutoCommit(false);
System.out.println("2. 事务已开启(现在执行的SQL不会立即保存)");
// ========== 第三步:检查余额 ==========
String checkSql = "SELECT balance FROM t_account WHERE id = ?";
PreparedStatement checkStmt = connection.prepareStatement(checkSql);
checkStmt.setInt(1, fromId);
resultSet = checkStmt.executeQuery();
if (!resultSet.next()) {
throw new RuntimeException("转出账户不存在!ID: " + fromId);
}
double balance = resultSet.getDouble("balance");
System.out.println("3. 检查余额:当前有 " + balance + " 元");
if (balance < amount) {
throw new RuntimeException("余额不足!需要 " + amount + " 元,但只有 " + balance + " 元");
}
System.out.println(" 余额充足,可以继续");
// ========== 第四步:转出操作(扣钱) ==========
String sqlFrom = "UPDATE t_account SET balance = balance - ? WHERE id = ?";
pstmtFrom = connection.prepareStatement(sqlFrom);
pstmtFrom.setDouble(1, amount); // 设置扣款金额
pstmtFrom.setInt(2, fromId); // 设置扣款账户
pstmtFrom.executeUpdate();
System.out.println("4. 执行转出:从账户" + fromId + "扣除 " + amount + " 元");
System.out.println(" (注意:此时还没有真正保存,只是临时修改)");
// ========== 第五步:转入操作(加钱) ==========
String sqlTo = "UPDATE t_account SET balance = balance + ? WHERE id = ?";
pstmtTo = connection.prepareStatement(sqlTo);
pstmtTo.setDouble(1, amount); // 设置入账金额
pstmtTo.setInt(2, toId); // 设置入账账户
int rowsTo = pstmtTo.executeUpdate();
System.out.println("5. 执行转入:向账户" + toId + "增加 " + amount + " 元");
// 检查转入账户是否存在
if (rowsTo == 0) {
throw new RuntimeException("转入账户不存在!ID: " + toId);
}
// ========== 第六步:提交事务(真正保存) ==========
// 所有操作都成功了,现在把所有修改永久保存到数据库
connection.commit();
System.out.println("6. ✓ 提交事务:所有修改已永久保存");
System.out.println(" 转账完成!金额: " + amount + " 元");
return true;
} catch (Exception e) {
// ========== 第七步:回滚事务(撤销所有修改) ==========
// 如果上面任何一步出错了,就撤销所有已经做的修改
System.out.println("\n ✗ 发生错误:" + e.getMessage());
if (connection != null) {
try {
connection.rollback(); // 回滚:撤销所有未提交的修改
System.out.println(" ✗ 已回滚:所有修改已撤销,数据恢复原样");
} catch (SQLException ex) {
System.err.println(" ✗ 回滚失败!");
ex.printStackTrace();
}
}
return false;
} finally {
// ========== 第八步:清理资源 ==========
// 恢复自动提交模式(为了不影响其他操作)
if (connection != null) {
try {
connection.setAutoCommit(true);
} catch (SQLException e) {
e.printStackTrace();
}
}
// 关闭所有数据库资源
JdbcUtil.close(resultSet, pstmtFrom, connection);
if (pstmtTo != null) {
try {
pstmtTo.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
/**
* 查看所有账户的余额
*/
private static void showAllAccounts() {
Connection connection = null;
PreparedStatement pstmt = null;
ResultSet resultSet = null;
try {
connection = JdbcUtil.getConnection();
String sql = "SELECT id, username, balance FROM t_account ORDER BY id";
pstmt = connection.prepareStatement(sql);
resultSet = pstmt.executeQuery();
System.out.println(" ID | 用户名 | 余额");
System.out.println(" -------------------");
while (resultSet.next()) {
int id = resultSet.getInt("id");
String username = resultSet.getString("username");
double balance = resultSet.getDouble("balance");
System.out.printf(" %d | %-6s | %.2f%n", id, username, balance);
}
} catch (Exception e) {
System.err.println(" 查询失败:" + e.getMessage());
} finally {
JdbcUtil.close(resultSet, pstmt, connection);
}
}
}
9.5 编译运行(示例)
javac -encoding UTF-8 JdbcUtil.java JdbcTransaction.java
java JdbcTransaction
(其他类同理,把需要编译的 .java 一起写上即可。)
十、总结
工具类把驱动、URL、账号密码和关闭资源集中管理,业务代码更干净。
查询用 executeQuery,增删改用 executeUpdate,注意在 finally 中释放连接。
事务通过 setAutoCommit(false) + commit / rollback 保证转账等业务的数据一致性;示例中用 ? 占位符 的 PreparedStatement 更安全。
上线前建议:配置外置化(properties)、使用连接池(如 HikariCP)、并尽量全面关闭所有 Statement 资源。
说明:文中代码与注释来自个人学习项目;数据库名、表名、密码请按本机环境修改后再运行。若对你有帮助,欢迎点赞收藏。
更多推荐




所有评论(0)