近期观看论坛中有些朋友在学习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);
}
}
希望这个简单的封装,能够带给大家一定的启迪。
谢谢。