Java案例怎么封装JDBC工具类?

wen java案例 10

本文目录导读:

Java案例怎么封装JDBC工具类?

  1. 基础版JDBC工具类 (最常用)
  2. 增强版:支持事务管理
  3. 使用示例
  4. 最佳实践总结
  5. 进阶:使用连接池优化

在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代码将具备可配置性、易维护性、健壮性,是生产环境的标配做法。

抱歉,评论功能暂时关闭!