简易JDBC框架实现过程详解

 更新时间:2020年02月25日 10:29:53   作者:---WeiGeH  
这篇文章主要介绍了简易JDBC框架实现过程详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下

1 准备

  • JDBC 基本知识
  • JDBC元数据知识
  • 反射基本知识

2: 两个问题

业务背景:系统中所有实体对象都涉及到基本的CRUD操作。所有实体的CUD操作代码基本相同,仅仅是发送给数据库的sql语句不同而已,因此可以把CUD操作的所有相同代码抽取到工具类的一个update方法中,并定义参数接收变化的sql语句。

实体的R操作,除sql语句不同之外,根据操作的实体不同,对ResultSet的映射也各不相同,因此可定义一个query方法,除以参数形式接收变化的sql语句外,可以使用策略模式由query方法的调用者决定如何把ResultSet中的数据映射到实体对象中。

3: JDBC 封装 update query方法

public class JdbcNewUtils {
  private JdbcNewUtils() {}
  /**
   * 这里可以使用properties进行替换
   */
  private static final String USER = "root";
  private static final String PWD = "root";
  private static final String URL = "jdbc:mysql://127.0.0.1:3306/day?useUnicode=true&characterEncoding=utf8&serverTimezone=UTC&generateSimpleParameterMetadata=true";
  private static final String DRIVER= "com.mysql.jdbc.Driver";
  static {
    try {
      Class.forName(DRIVER);
    } catch (ClassNotFoundException e) {
      e.printStackTrace();
    }
  }
  
  public static Connection getConnection() throws SQLException {
    Connection connection = DriverManager.getConnection(URL, USER, PWD);
    return connection;
  }
  /**
   * CUD 返回影响数目
   * @param sql
   * @param args
   * @return int
   */
  public static int update(String sql,Object [] args) {
    PreparedStatement ps = null;
    Connection conn = null;
    try {
      conn=getConnection();
      ps = conn.prepareStatement(sql);
      for (int i = 1; i <= args.length; i++) {
        ps.setObject(i, args[i-1]);
      }
      return ps.executeUpdate();
    } catch (SQLException e) {
      e.printStackTrace();
    }finally {
      close(conn, ps);
    }
    return 0;
  }
  /**
   * 查询结果封装Bean
   * @param sql
   * @param args
   * @param rsh
   * @return Object
   */
  public static Object query(String sql,Object [] args,ResultSetHandler rsh) {
    PreparedStatement ps = null;
    Connection conn = null;
    try {
      conn=getConnection();
      ps = conn.prepareStatement(sql);
      for (int i = 0; i < args.length; i++) {
        ps.setObject(i+1, args[i]);
      }
      return rsh.handle(ps.executeQuery());
    } catch (SQLException e) {
      e.printStackTrace();
    }finally {
      close(conn, ps);
    }
    return null;
  }
  
  /**
  * 关闭所有打开的资源
  */
  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();
      }
    }
  }
  /**
  * 关闭所有打开的资源
  */
  public static void close(Connection conn, Statement stmt, ResultSet rs) {
    if(rs!=null) {
      try {
        rs.close();
      } catch (SQLException e) {
        e.printStackTrace();
      }
    }
    close(conn, stmt);
  }

}

4: query

每次查询根据查询的参数不同, 返回的ResultSet 也不同, 这个规则我们需要单独编写规则解析器, 这里用到了策略设计模式,

将ResultSetHandler 定义解决问题的接口, handle为那些需要实现的具体解决的办法

public interface ResultSetHandler {
  Object handle(ResultSet resultSet);
}

下面我实现了Beanhandler 和 BeanListHandler 分别是 单个的Bean 和一个列表的Bean

package jdbc.simpleframwork;

import java.lang.reflect.Field;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;

public class BeanHandler implements ResultSetHandler {

  private Class<?> obj;
  public BeanHandler(Class<?> obj) {
    this.obj = obj;
  }
  @Override
  public Object handle(ResultSet resultSet){
    try {
      if(!resultSet.next()) {
        return null;
      }
      Object instance = obj.newInstance();
      ResultSetMetaData metaData = resultSet.getMetaData();
      int count = metaData.getColumnCount();
      for(int i=1;i<=count;i++) {
        Field f = obj.getDeclaredField(metaData.getColumnName(i));
        f.setAccessible(true);
        f.set(instance, resultSet.getObject(i));
      }
      return instance;
    } catch (InstantiationException | IllegalAccessException e) {
      e.printStackTrace();
    } catch (SQLException e) {
      e.printStackTrace();
    } catch (NoSuchFieldException e) {
      e.printStackTrace();
    } catch (SecurityException e) {
      e.printStackTrace();
    }
    return null;
  }
}
package jdbc.simpleframwork;

import java.lang.reflect.Field;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.util.ArrayList;

public class BeanListHandler implements ResultSetHandler {

  private Class<?> clazz;

  public BeanListHandler(Class<?> clazz) {
    super();
    this.clazz = clazz;
  }

  @Override
  public Object handle(ResultSet resultSet) {
    try {
      ArrayList<Object> objlist = new ArrayList<>();
      ResultSetMetaData metaData = resultSet.getMetaData();
      int count = metaData.getColumnCount();
      while (resultSet.next()) {
        Object instace = clazz.newInstance();
        for (int i = 0; i < count; i++) {
          Field f = clazz.getDeclaredField(metaData.getColumnName(i + 1));
          f.setAccessible(true);
          f.set(instace, resultSet.getObject(i + 1));
          f.setAccessible(false);
        }
        objlist.add(instace);

      }
      return objlist;
    } catch (Exception e) {
      e.printStackTrace();
    }
    return null;
  }
}

5 测试

public class TestFramwork {

  public static void main(String[] args) throws SQLException {
    Connection conn = JdbcNewUtils.getConnection();

    String sql = "select * from student where id=?";
    PreparedStatement ps = conn.prepareStatement(sql);
    Student stu = (Student) JdbcNewUtils.query(sql, new Object[] { 1 }, new BeanHandler(Student.class));
    System.out.println(stu);

    String sql2 = "select * from student";
    ArrayList<Student> list = (ArrayList<Student>) JdbcNewUtils.query(sql2, new Object[] {},
        new BeanListHandler(Student.class));
    System.out.println(list);
  }

}

6: 总结

Update系列操作:

  对于CUD操作,SQL只有站位符号的多少发生了改变,对于传递参数才是我们需要关注的地方,但是JDBC提供了一系列传递参数解析的办法,通过set系列函数,将参数值传递进行,所以我们只需要封装一个通用的update即可
Query系列操作

  对R操作,就复杂得多,SQL语句的不同,返回的ResultSet也不同,可以单个Bean 或者一个List,一个Map等,可以看出来,实际上很多框架提供的也就是这些方法的封装

对了 真正应用上 我们的DAO 一边是 下面的写法

public class AccountDao {
  public void add(Account account) throws SQLException{
    String sql = "insert into account(name , money) values(?, ?)";
    Object[] params = {account.getName(), account.getMoney()};
    JdbcUtils.update(sql, params);
  }
  
  public void delete(int id ) throws SQLException{
    String sql = "delete from account where id = ?";
    Object[] params = {id};
    JdbcUtils.update(sql, params);
  }
  
  public void update(Account account) throws SQLException{
    String sql = "update account set name = ?, money = ? where id = ?";
    Object params[] = {account.getName(), account.getMoney(), account.getId()};
    JdbcUtils.update(sql, params);
  }
  
  public Account find(int id ) throws SQLException{
    String sql = "select * from account where id = ?";
    Object params[] = {id};
    return (Account) JdbcUtils.query(sql, params, new BeanHandler(Account.class));
  }
  
  public List getAll() throws SQLException{
    String sql = "select * from account";
    Object params[] = {};
    return (List)JdbcUtils.query(sql, params, new BeanListHandler(Account.class));
  }
}

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。

相关文章

  • java捕获AOP级别的异常并将其传递到Controller层

    java捕获AOP级别的异常并将其传递到Controller层

    如何在一个现代的Java应用中,捕获AOP(面向切面编程)级别的异常,并将这些异常传递到Controller层进行合适的处理,异常处理在构建可靠的应用程序中起着关键作用,而AOP则可以帮助我们更好地管理和组织代码,我们将深入研究如何结合AOP和异常处理来构建健壮的应用
    2023-09-09
  • Java中Spring技巧之扩展点的应用

    Java中Spring技巧之扩展点的应用

    这篇文章主要介绍了Java中Spring技巧之扩展点的应用,下文Spring容器的启动流程图展开其内容的相关资料,具有一定的参考价值,需要的小伙伴可以参考一下
    2022-04-04
  • 使用 mybatis 自定义日期类型转换器的示例代码

    使用 mybatis 自定义日期类型转换器的示例代码

    这篇文章主要介绍了使用 mybatis 自定义日期类型转换器的示例代码,这里使用mybatis中的typeHandlers 实现的,本文通过实例代码给大家介绍的非常详细,需要的朋友可以参考下
    2022-03-03
  • Java JDBC导致的反序列化攻击原理解析

    Java JDBC导致的反序列化攻击原理解析

    这篇文章主要介绍了Java JDBC导致的反序列化攻击原理解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2019-12-12
  • Eclipse搭建spring开发环境图文教程(推荐)

    Eclipse搭建spring开发环境图文教程(推荐)

    下面小编就为大家带来一篇Eclipse搭建spring开发环境图文教程(推荐)。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-07-07
  • JavaCV获取视频文件时长的方法

    JavaCV获取视频文件时长的方法

    这篇文章主要为大家详细介绍了JavaCV获取视频文件时长的方法,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2019-07-07
  • 基于mybatis 动态SQL查询总结

    基于mybatis 动态SQL查询总结

    这篇文章主要介绍了mybatis 动态SQL查询总结,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-07-07
  • spring 注解如何开启声明式事务

    spring 注解如何开启声明式事务

    这篇文章主要介绍了spring 注解开启声明式事务问题,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-12-12
  • 详解Java的TCP/IP编程学习--基于定界符的成帧

    详解Java的TCP/IP编程学习--基于定界符的成帧

    这篇文章主要介绍了Java的TCP/IP编程学习--基于定界符的成帧,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-04-04
  • POI XSSFSheet shiftRows bug问题解决

    POI XSSFSheet shiftRows bug问题解决

    这篇文章主要介绍了POI XSSFSheet shiftRows bug问题解决,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-07-07

最新评论