简易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));
  }
}

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

(0)

相关推荐

  • 在Java的Spring框架的程序中使用JDBC API操作数据库

    同时与数据库使用普通的旧JDBC的工作,它变得繁琐写不必要的代码来处理异常,打开和关闭数据库连接等,但Spring的JDBC框架需要的所有低层次细节从打开连接,准备和执行SQL语句,过程异常,处理事务,最后关闭连接. 所以,你所要做的只是定义连接参数,并指定要执行的SQL语句,并做必要的工作,在每次迭代时从数据库中获取数据. Spring JDBC提供了一些方法和相应不同的类与数据库进行交互.我要采取经典和最流行的做法,利用JdbcTemplateclass框架.这是管理的所有数据库的通信和异常

  • Java使用JDBC或MyBatis框架向Oracle中插入XMLType数据

    先来了解一下什么是XMLType类型. XMLType是Oracle从9i开始特有的数据类型,是一个继承了Blob的强大存在,可以用来存储xml并提供了相当多的操作函数.理论上可以保存2G大小的数据. 那怎么样通过java来插入XMLType类型的数据呢?项目当中采用的是Mybatis,总是出现莫名的异常,都搞不清楚到底是Mybatis的问题还是jdbc本身的问题,所以打算一步步来,先搞定jdbc,再解决Mybatis. JDBC 在折腾了半天之后,发现jdbc操作主要有3种方法: 一.在Jav

  • Java基础开发之JDBC操作数据库增删改查,分页查询实例详解

    对数据库的操作无非就是增删改查,其中数查询操作最为复杂,所以将查询单独讲解,我这里用的Mysql数据库 增删改查操作 分页查询操作 1.查询结果以list返回 2.查询结果以jsonArray返回 3.查询总记录条数 先看一下相关的配置信息 public static final String USER_NAME = "root"; public static final String PWD = "123456789"; public static final S

  • java开发之Jdbc分页源码详解

    总之是用jdbc 的游标移动 package com.sp.person.sql.util; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.util.Map; import java.util.TreeMap; import javax.sql.DataSource; /** *

  • JDBC连接MySQL数据库批量插入数据过程详解

    这篇文章主要介绍了JDBC连接MySQL数据库批量插入数据过程详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 1.读取本地json数据 2.jdbc理解数据库 3.批量插入 maven 引入jar包: <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2

  • 5分钟快速学会spring boot整合JdbcTemplate的方法

    一.前言 Spring Boot是由Pivotal团队提供的全新框架,其设计目的是用来简化新Spring应用的初始搭建以及开发过程.该框架使用了特定的方式来进行配置,从而使开发人员不再需要定义样板化的配置.通过这种方式,Spring Boot致力于在蓬勃发展的快速应用开发领域(rapid application development)成为领导者.本文主要介绍的是关于springboot整合JdbcTemplate. 在此记录下,分享给大家. 二.springboot整合JdbcTemplate

  • java数据库开发之JDBC的完整封装兼容多种数据库

    目前此代码我只用过mysql和oracle数据库测试过,但相信其它数据库都是可以的,只要导入你需要操作的数据库jar包,驱动等就可,下面上代码: import java.sql.CallableStatement; import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.Resul

  • 简易JDBC框架实现过程详解

    1 准备 JDBC 基本知识 JDBC元数据知识 反射基本知识 2: 两个问题 业务背景:系统中所有实体对象都涉及到基本的CRUD操作.所有实体的CUD操作代码基本相同,仅仅是发送给数据库的sql语句不同而已,因此可以把CUD操作的所有相同代码抽取到工具类的一个update方法中,并定义参数接收变化的sql语句. 实体的R操作,除sql语句不同之外,根据操作的实体不同,对ResultSet的映射也各不相同,因此可定义一个query方法,除以参数形式接收变化的sql语句外,可以使用策略模式由que

  • Python3+RIDE+RobotFramework自动化测试框架搭建过程详解

    Python2.7已于2020年1月1日开始停用,之前RF做自动化都是基于Python2的版本. 没办法,跟随时代的脚步,我们也不得不升级以应用新的控件与功能. 升级麻烦,直接全新安装. 一.Python安装 最新版Python下载地址:https://www.python.org/ 根据操作系统选择对应版本制品下载安装即可,本机用的是Windows x86-64 executable installer. 注意事项: 安装完成后检查下环境变量,默认会配置好,可以检查下. 检测是否安装成功,可在

  • python miniWeb框架搭建过程详解

    框架概念 框架和web服务器关系 ·静态资源:不是经常变化的资源.往往是固定不变的资源 ·动态资源:经常变化的资源 ·模板文件:提供了一个显示的模板,显示的内容不同,但是结构是一样的 ·服务器的作用: o1)接受客户端请求 o2)响应客户端请求 o3)调用应用框架获取 miniWeb框架构建基本构建 ·思路: o判断请求的资源路径是 是否是 .py 结尾 o如果 .py 结尾,--> 显示动态内容 o如果.html 结尾,--> 显示静态内容 ·核心代码: 核心代码: # index.py

  • java开发分布式服务框架Dubbo暴露服务过程详解

    目录 Dubbo服务暴露机制 前言 服务暴露流程 源码解析 本地暴露 远程暴露 Dubbo服务暴露机制 前言 在进行服务暴露机制的分析之前,必须谈谈什么是URL,在Dubbo服务暴露过程中URL是无处不在的,贯穿了整个过程. 一般情况下,URL指的是统一资源定位符,标准格式如下: protocol://host:port/path?key1=value1&key2=value2 Dubbo就是用这种URL的方式来作为约定的参数类型,服务之间也是用URL来进行交互. Dubbo用URL作为配置总线

  • java property配置文件管理工具框架过程详解

    这篇文章主要介绍了java property配置文件管理工具框架过程详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 property property 是 java 实现的 property 框架. 特点 优雅地进行属性文件的读取和更新 写入属性文件后属性不乱序 灵活定义编码信息 使用 OO 的方式操作 property 文件 支持多级对象引用 快速开始 环境依赖 Maven 3.x Jdk 1.7+ Maven 引入依赖 <depende

  • spring整合Quartz框架过程详解

    这篇文章主要介绍了spring整合Quartz框架过程详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 1.Quartz框架简介 Quartz是一个完全由Java编写的开源任务调度的框架,通过触发器设置作业定时运行规则,控制作业的运行时间.其中quartz集群通过故障切换和负载平衡的功能,能给调度器带来高可用性和伸缩性.主要用来执行定时任务,如:定时发送信息.定时生成报表等等. Quartz框架的主要特点: · 强大的调度功能,例如丰富多样的

  • Spring框架实现AOP添加日志记录功能过程详解

    这篇文章主要介绍了Spring框架实现AOP添加日志记录功能过程详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 需求,在调用业务方法的时候,在被调用的业务方法的前面和后面添加上日志记录功能 整体架构: 日志处理类: package aop; import java.util.Arrays; import org.apache.log4j.Logger; import org.aspectj.lang.JoinPoint; //日志处理类 增

  • JDBC自定义连接池过程详解

    这篇文章主要介绍了JDBC自定义连接池过程详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 开发中,"获得连接"和"释放资源"是非常消耗系统资源的,为了解决此类性能问题可以采用连接池技术来共享连接Connection. 1.概述 用池来管理Connection,这样可以重复使用Connection.这样我们就不用创建Connection,用池来管理Connection对象,当使用完Connection对象后,将C

  • TinkerPop框架查询Gremlin图实现过程详解

    目录 前言 肇始于 TinkerPop 文档 Structure 接口结构与实现思路 Graph 接口 Element 接口 Vertex 接口 Edge 接口 Property 接口 VertexProperty 接口 实现自己的 Structure 更进一步 前言 本文记录了笔者摸索图数据库过程中遇到的问题.一些思考(闲谈)与实现思路. 做此记录的目的是沉淀经验.完善巩固知识体系,同时以此为始,培养撰写文本.输出内容的能力与习惯. 本文内容源自笔者自身见识,仅为一家之言,不足之处望诸位批评指

随机推荐