本文目录导读:

在Java中封装JDBC工具类的核心目的是减少重复代码、统一资源管理、提高可维护性,以下是业界常用且稳健的封装方案,包含完整代码和最佳实践。
基础版JDBC工具类 (最常用)
import java.io.InputStream;
import java.sql.*;
import java.util.Properties;
public class JDBCUtils {
private static String driver;
private static String url;
private static String username;
private static String password;
// 静态代码块:类加载时执行一次,读取配置文件
static {
try {
// 方式1:读取classpath下的jdbc.properties
InputStream is = JDBCUtils.class.getClassLoader()
.getResourceAsStream("db.properties");
Properties props = new Properties();
props.load(is);
driver = props.getProperty("jdbc.driver");
url = props.getProperty("jdbc.url");
username = props.getProperty("jdbc.username");
password = props.getProperty("jdbc.password");
// 注册驱动
Class.forName(driver);
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException("数据库连接失败!", e);
}
}
/**
* 获取数据库连接
*/
public static Connection getConnection() throws SQLException {
return DriverManager.getConnection(url, username, password);
}
/**
* 释放资源(用于查询操作)
*/
public static void close(Connection conn, Statement stmt, ResultSet rs) {
if (rs != null) {
try {
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
close(conn, stmt);
}
/**
* 释放资源(用于增删改操作,无结果集)
*/
public static void close(Connection conn, Statement stmt) {
if (stmt != null) {
try {
stmt.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (conn != null) {
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
对应配置文件 db.properties (放在src根目录):
jdbc.driver=com.mysql.cj.jdbc.Driver jdbc.url=jdbc:mysql://localhost:3306/mydb?useSSL=false&serverTimezone=UTC jdbc.username=root jdbc.password=123456
增强版:支持事务管理
import java.sql.Connection;
import java.sql.SQLException;
/**
* 增强版:支持手动事务控制
*/
public class JDBCUtilsEnhanced {
// 使用ThreadLocal保证每个线程独立Connection
private static ThreadLocal<Connection> tl = new ThreadLocal<>();
/**
* 获取当前线程的Connection(支持事务)
*/
public static Connection getCurrentConnection() throws SQLException {
Connection conn = tl.get();
if (conn == null) {
conn = JDBCUtils.getConnection();
tl.set(conn);
}
return conn;
}
/**
* 开启事务
*/
public static void beginTransaction() throws SQLException {
Connection conn = getCurrentConnection();
conn.setAutoCommit(false);
}
/**
* 提交事务
*/
public static void commitTransaction() throws SQLException {
Connection conn = getCurrentConnection();
if (conn != null) {
conn.commit();
conn.setAutoCommit(true); // 恢复自动提交
}
}
/**
* 回滚事务
*/
public static void rollbackTransaction() throws SQLException {
Connection conn = getCurrentConnection();
if (conn != null) {
conn.rollback();
conn.setAutoCommit(true);
}
}
/**
* 清除ThreadLocal中的连接(重要!)
*/
public static void closeConnection() throws SQLException {
Connection conn = tl.get();
if (conn != null) {
conn.close();
tl.remove(); // 必须清除,防止内存泄漏
}
}
}
使用示例
1 查询操作
public List<User> findAllUsers() {
String sql = "SELECT * FROM users";
List<User> list = new ArrayList<>();
Connection conn = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
try {
conn = JDBCUtils.getConnection();
pstmt = conn.prepareStatement(sql);
rs = pstmt.executeQuery();
while (rs.next()) {
User user = new User();
user.setId(rs.getInt("id"));
user.setName(rs.getString("name"));
list.add(user);
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
// 注意释放顺序:ResultSet -> Statement -> Connection
JDBCUtils.close(conn, pstmt, rs);
}
return list;
}
2 事务操作
public void transferMoney(int fromId, int toId, double amount) {
Connection conn = null;
PreparedStatement pstmt1 = null;
PreparedStatement pstmt2 = null;
try {
// 1. 获取连接并开启事务
conn = JDBCUtilsEnhanced.getCurrentConnection();
JDBCUtilsEnhanced.beginTransaction();
// 2. 执行两个更新操作
String sql1 = "UPDATE account SET money = money - ? WHERE id = ?";
pstmt1 = conn.prepareStatement(sql1);
pstmt1.setDouble(1, amount);
pstmt1.setInt(2, fromId);
pstmt1.executeUpdate();
// 模拟异常
// int i = 1/0;
String sql2 = "UPDATE account SET money = money + ? WHERE id = ?";
pstmt2 = conn.prepareStatement(sql2);
pstmt2.setDouble(1, amount);
pstmt2.setInt(2, toId);
pstmt2.executeUpdate();
// 3. 提交事务
JDBCUtilsEnhanced.commitTransaction();
} catch (SQLException e) {
try {
JDBCUtilsEnhanced.rollbackTransaction();
} catch (SQLException ex) {
ex.printStackTrace();
}
e.printStackTrace();
} finally {
// 释放资源
JDBCUtils.close(conn, pstmt1);
JDBCUtils.close(null, pstmt2);
// 清除ThreadLocal
try {
JDBCUtilsEnhanced.closeConnection();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
最佳实践总结
| 要点 | 说明 |
|---|---|
| 配置文件 | 使用 .properties 或 .yml 避免硬编码 |
| 驱动注册 | 静态代码块执行一次,避免重复注册 |
| 资源释放 | 遵循 ResultSet → Statement → Connection 顺序 |
| 关闭判断 | 每个资源关闭前判断 null,防止空指针 |
| ThreadLocal | 事务场景必备,确保同一线程共用连接 |
| finally块 | 确保资源在任何情况下都被释放 |
| 异常处理 | 使用 printStackTrace() 或日志记录,避免吞异常 |
进阶:使用连接池优化
import com.alibaba.druid.pool.DruidDataSourceFactory;
import javax.sql.DataSource;
import java.util.Properties;
public class JDBCPoolUtils {
private static DataSource dataSource;
static {
try {
Properties props = new Properties();
props.load(JDBCPoolUtils.class.getClassLoader()
.getResourceAsStream("druid.properties"));
dataSource = DruidDataSourceFactory.createDataSource(props);
} catch (Exception e) {
e.printStackTrace();
}
}
public static Connection getConnection() throws SQLException {
return dataSource.getConnection();
}
// 其他方法同JDBCUtils(close方法不需要关闭真正的连接,而是归还到连接池)
}
druid.properties:
driverClassName=com.mysql.cj.jdbc.Driver url=jdbc:mysql://localhost:3306/mydb username=root password=123456 initialSize=5 maxActive=10
这样封装后,你的JDBC代码将具备可配置性、易维护性、健壮性,是生产环境的标配做法。