JDBC操作的简单封装

近期观看论坛中有些朋友在学习JDBC操纵数据库,于是,突发奇想打算封装一下JDBC的操作,希望能够通过二次封装,简化一下常规操作,当然,也就当是练练手了。

一、JDBC 的常规操作

      JDBC 的常规操作分为两类,执行SQL语句 和 调用存储过程。调用存储过程,这个对于新手来说,不太常用,所以,暂时就不进行封装了。

      执行SQL语句的话,一般分为 增删改查 这四类操作。其中 增删改,可以统一使用 executeUpdate 进行操作,查询可以使用 executeQuery 进行操作。

二、JDBC 的操作步骤

     1. 加载驱动      

Class.forName(“oracle.jdbc.driver.OracleDriver”);

     2. 获取数据库连接

Connection connection = DriverManager.getConnection(url, user, password);

     3. 执行 SQL 语句

PreparedStatement pstm = connection.prepareStatement(sql);
ResultSet rs = pstm.executeQuery();//查询
int updated = pstm.executeUpdate();//增删改

    4. 释放资源

rs.close();
pstm.close();
connection.close();

三、设计思路

    1. 我们要进行封装的是数据库操纵的过程,所以,考察的目标应该是上述四个操作步骤;

    2. 获取数据库连接这个操作,可以采用工厂模式,提取出一个 ConnectionFactory 接口,专门用于创建数据库连接,当然,加载数据库驱动的操作也可以包含在里面。

    3. 执行的 SQL 语句分为查询和更新两种操作。更新操作的结果比较简单,返回受影响的记录数即可;查询操作返回的是结果集对象,我们还需要遍历结果集,将遍历的结果返回。遍历的结果数据存在一个转换过程,将结果数据转换成用户自定义的JavaBean对象,这就需要我们定义一个 ResultSetConverter 接口,用于让用户自己定义 ResultSet 向JavaBean(POJO)的转换过程。

    4. 数据库的操作过程,应该进行数据库事务的封装,这样的话,多个数据库操作可以封装到同一个数据库事务当中,如果中间环节出现问题,事务自动进行回滚即可。

四、小结

    1. 我们需要定义一个 ConnectionFactory 接口,用于获取(创建)数据库连接。

    2. 我们需要定义一个 ResultSetConverter 接口, 用于用户自己定义查询结果的转换。

    3. 我们需要先封装一下单次的数据库操作过程,然后再将多个单次的操作封装到数据库事务当中。

    4. 创建 JdbcAction 类,封装单次数据库操作(查询/更新操作)。

    5. 创建 JdbcFacde 类,封装数据库事务,用户可以自定义在一个事务中进行多次数据库操作。

五、上代码

package hl.jdbc;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;

/**
 * 数据库连接的工厂类,创建数据库连接。
 */
public interface ConnectionFactory {
    Connection create() throws SQLException;

    class Default implements ConnectionFactory {

        private final String driverClass;
        private final String url;
        private final String user;
        private final String password;

        /**
         * 默认的连接工厂
         */
        public Default(String driverClass, String url, String user, String password) {
            this.driverClass = driverClass;
            this.url = url;
            this.user = user;
            this.password = password;
            try {
                Class.forName(driverClass);
            } catch (ClassNotFoundException e) {
                throw new IllegalStateException("create jdbc connection failed.", e);
            }
        }

        @Override
        public Connection create() throws SQLException {
            return DriverManager.getConnection(url, user, password);
        }
    }
}
package hl.jdbc;

import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;

/**
 * 查询结果的转换器
 * @param <R> POJO/JavaBean 的类型
 */
public interface ResultSetConverter<R> {

    /** 转换函数 */
    R convert(ResultSet rs) throws SQLException;

    /** 转换前会调用该函数,传递查询结果的列信息 如果需要的话,可以重写改函数 */
    default void setResultSetMetaData(ResultSetMetaData rsmd) throws SQLException {}

    /**
     * 提供默认的转换器,将查询结果的记录转换成 HashMap 对象
     */
    class Default implements ResultSetConverter<Map<String, Object>> {

        private HashSet<String> columNames = new HashSet<>();
        @Override
        public void setResultSetMetaData(ResultSetMetaData rsmd) throws SQLException {
            for (int i=1; i <= rsmd.getColumnCount(); i++) {
                columNames.add(rsmd.getColumnName(i));
            }
        }

        @Override
        public Map convert(ResultSet rs) throws SQLException {
            HashMap<String, Object> record = new HashMap<>();
            for (String name : columNames) {
                record.put(name, rs.getObject(name));
            }
            return record;
        }

    }
}
package hl.jdbc;

import java.sql.*;
import java.util.*;

/**
 * 数据库操作的封装类,每个函数都可以完成一次数据库的访问。
 */
public class JdbcAction {

    private final Connection conn;

    public JdbcAction(Connection conn) {
        this.conn = conn;
    }

    /** 更新操作 */
    public int executeUpdate(String sql, Object ... params) throws SQLException {
        try (PreparedStatement pstm = conn.prepareStatement(sql)) {
            if (params != null && params.length > 0) {
                for (int i = 1; i <= params.length; i++) {
                    pstm.setObject(i, params[i - 1]);
                }
            }
            return pstm.executeUpdate();
        }
    }

    /** 查询操作 */
    public <R>List<R> executeQuery(ResultSetConverter<R> converter, String sql, Object ...params) throws SQLException {
        try (PreparedStatement pstm = conn.prepareStatement(sql)) {
            if (params != null && params.length > 0) {
                for (int i = 1; i <= params.length; i++) {
                    pstm.setObject(i, params[i - 1]);
                }
            }
            try (ResultSet rs = pstm.executeQuery()) {
                List<R> result = new ArrayList<>();
                converter.setResultSetMetaData(rs.getMetaData());
                while (rs.next()) {
                    R record = converter.convert(rs);
                    result.add(record);
                }
                return result;
            }
        }
    }

    /** 查询操作 */
    public List<Map<String, Object>> executeQuery(String sql, Object ...params) throws SQLException {
        return executeQuery(new ResultSetConverter.Default(), sql, params);
    }

    /** 查询操作,只有一条记录返回 */
    public <R> R executeQueryUnique(ResultSetConverter<R> converter, String sql, Object ...params) throws SQLException {
        try (PreparedStatement pstm = conn.prepareStatement(sql)) {
            if (params != null && params.length > 0) {
                for (int i = 1; i <= params.length; i++) {
                    pstm.setObject(i, params[i - 1]);
                }
            }
            try (ResultSet rs = pstm.executeQuery()) {
                converter.setResultSetMetaData(rs.getMetaData());
                if (rs.next()) {
                    R record = converter.convert(rs);
                    return record;
                }
                return null;
            }
        }
    }

    /** 查询操作,只有一条记录返回 */
    public Map<String, Object> executeQueryUnique(String sql, Object ...params) throws SQLException {
        return executeQueryUnique(new ResultSetConverter.Default(), sql, params);
    }

}
package hl.jdbc;

import java.sql.Connection;
import java.sql.SQLException;
import java.util.List;
import java.util.Map;

/**
 * 数据库事务的封装类,通过接口回调完成事务封装。
 */
public class JdbcFacade {

    /** 数据库操作的封装接口,实现类中添加一个事务中具体的数据库操作。 **/
    public interface TransactionAction<R> {
        R execute(JdbcAction action) throws SQLException;
    }

    private final ConnectionFactory factory;

    public JdbcFacade(ConnectionFactory factory) {
        this.factory = factory;
    }

    /** 核心功能函数,通过接口回调完成事务的封装 */
    public <R> R executeTransaction(TransactionAction<R> transaction) throws SQLException {
        Connection conn = factory.create();
        boolean autoCommit = conn.getAutoCommit();
        if (autoCommit) {
            conn.setAutoCommit(false);
        }
        JdbcAction action = new JdbcAction(conn);
        try {
            R result = transaction.execute(action);
            conn.commit();
            return result;
        } catch (Exception ex) {
            conn.rollback();
            throw ex;
        } finally {
            if (conn.getAutoCommit() != autoCommit) {
                conn.setAutoCommit(autoCommit);
            }
        }
    }

    /** 特化操作,一个事务只进行一次更新操作 **/
    public int executeUpdate(String sql, Object ... params) throws SQLException {
        return executeTransaction(action -> action.executeUpdate(sql, params));
    }

    /** 特化操作,一个事务只进行一次查询操作 **/
    public <R> List<R> executeQuery(ResultSetConverter<R> converter, String sql, Object ...params) throws SQLException {
        return executeTransaction(action -> action.executeQuery(converter, sql, params));
    }

    /** 特化操作,一个事务只进行一次查询操作 **/
    public List<Map<String, Object>> executeQuery(String sql, Object ...params) throws SQLException {
        return executeTransaction(action -> action.executeQuery(sql, params));
    }

    /** 特化操作,一个事务只进行一次查询操作 **/
    public <R> R executeQueryUnique(ResultSetConverter<R> converter, String sql, Object ...params) throws SQLException {
        return executeTransaction(action -> action.executeQueryUnique(converter, sql, params));
    }

    /** 特化操作,一个事务只进行一次查询操作 **/
    public Map<String, Object> executeQueryUnique(String sql, Object ...params) throws SQLException {
        return executeTransaction(action -> action.executeQueryUnique(sql, params));
    }

}

整个封装过程完毕,上述代码仅用于学习和交流,请不要将这些代码进行商业用途或出售转卖。

六、简单的用例

package hl.jdbc;

import java.sql.SQLException;
import java.util.List;
import java.util.Map;

public class Useage {

    public static void main(String[] args) throws SQLException {
        final String driverClass = "oracle.jdbc.driver.OracleDriver";
        final String url = "jdbc:oracle:thin:@***.***.***.***:1625:*****”;
        final String user = "***”;
        final String password = "***”;
        ConnectionFactory factory = new ConnectionFactory.Default(driverClass, url, user, password);
        JdbcFacade facade = new JdbcFacade(factory);

        List<Map<String, Object>> result = facade.executeQuery("SELECT * FROM TB_MESSAGE ");
        for (Map<String, Object> record : result) {
            System.out.println(record);
        }

        int count = facade.executeQueryUnique(rs -> rs.getInt(1), "SELECT COUNT(1) FROM TB_MESSAGE");
        System.out.println(count);
    }

}

希望这个简单的封装,能够带给大家一定的启迪。

谢谢。

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值