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

实现简易JDBC框架的更多相关文章

  1. 简易RPC框架-SPI

    *:first-child { margin-top: 0 !important; } body > *:last-child { margin-bottom: 0 !important; } ...

  2. java web学习总结(二十三) -------------------编写自己的JDBC框架

    一.元数据介绍 元数据指的是"数据库"."表"."列"的定义信息. 1.1.DataBaseMetaData元数据 Connection.g ...

  3. Spring的JDBC框架

    转自: http://www.cnblogs.com/windlaughing/p/3287750.html Spring JDBC提供了一套JDBC抽象框架,用于简化JDBC开发. Spring主要 ...

  4. 【总结】编写自己的JDBC框架

    一.数据库连接池: 在一般用JDBC 进行连接数据库进行CRUD操作时,每一次都会: 通过:java.sql.Connection conn = DriverManager.getConnection ...

  5. jdbc框架 commons-dbutils+google guice+servlet 实现一个例子

    最近闲着无聊,于是看了一下jdbc框架 commons-dbutils与注入google guice. 我就简单的封装了一下代码,效率还是可以的.... jdbc+google guice+servl ...

  6. JDBC 学习笔记(四)—— 自定义JDBC框架+Apache—DBUtils框架+事务管理+操作多表

    本文目录:       1.自定义JDBC框架 ——数据库元数据:DataBaseMetaData        2.自定义JDBC框架 ——数据库元数据:DataBaseMetaData       ...

  7. javaweb学习总结(四十)——编写自己的JDBC框架

    一.元数据介绍 元数据指的是"数据库"."表"."列"的定义信息. 1.1.DataBaseMetaData元数据 Connection.g ...

  8. JDBC框架

    一.元数据介绍 元数据指的是"数据库"."表"."列"的定义信息. 1.1.DataBaseMetaData元数据 Connection.g ...

  9. 编写自定义的JDBC框架与策略模式

    本篇根据上一篇利用数据库的几种元数据来仿造Apache公司的开源DbUtils工具类集合来编写自己的JDBC框架.也就是说在本篇中很大程度上的代码都和DbUtils中相似,学完本篇后即更容易了解DbU ...

随机推荐

  1. 常用注解解析(因为不太明白@component和@configuration写了)

    1.@controller 控制器(注入服务) 用于标注控制层,相当于struts中的action层 2.@service 服务(注入dao) 用于标注服务层,主要用来进行业务的逻辑处理 3.@rep ...

  2. September 08th, 2019. Sunday, Week 37th.

    A heavy drew refreshed the earth at night. 夜晚厚重的露水滋养着大地. From Leo Tolstoy. Today is the White Drew D ...

  3. 07-Django视图进阶

    1.调试模式 Django项目下的settings.py 默认是DEBUG=True,开发的时候一般要开启调试模式,当项目完成发布必须要改成False,否则会暴露网站的配置信息,修改以下两行: # D ...

  4. 【docker部署】基于linux的centos操作系统部署安装docker容器

    一.docker介绍 容器是轻量级的,包含应用运行所需所有东西(代码.库.运行时环境.系统设置,以及依赖关系)的独立的包.每个容器都部署于它自己的 CPU.内存.块 I/O,以及网络资源上,所有这些都 ...

  5. C++入门到理解阶段二基础篇(7)——C++函数

    目录 函数作用 函数定义 函数声明 函数调用 函数值传递 函数常见的样式 函数的分文件书写 函数作用 将经常使用的代码封装起来,减少重复代码 函数定义 C++ 中的函数定义的一般形式如下: retur ...

  6. python中list常用的方法

    Python 列表    list    (以下内容为比较初级适合小白查看的笔记)   一.介绍: 列表是Python中内置有序.可变序列,列表的所有元素放在一对中括号“[]”中,并使用逗号分隔开: ...

  7. SSH框架之Hibernate第二篇

    1.1 持久化类的编写规则 1.1.1 什么是持久化类? 持久化类 : 与表建立了映射关系的实体类,就可以称之为持久化类. 持久化类 = Java类 + 映射文件. 1.1.2 持久化类的编写规则 ( ...

  8. JS基础语法---总结

    JS是一门什么样的语言? 是一门解释性的语言 是一门脚本语言 是一门弱类型语言,声明变量都用var 是一门基于对象的语言 是一门动态类型的语言:            1. 代码(变量)只有执行到这个 ...

  9. vue非父子关系之间通信传值

    第一种方法: 通过给vue实例添加自定义属性 <!DOCTYPE html> <html> <head> <meta charset="utf-8& ...

  10. Cobalt Strike系列教程第四章:文件/进程管理与键盘记录

    Cobalt Strike系列教程分享如约而至,新关注的小伙伴可以先回顾一下前面的内容: Cobalt Strike系列教程第一章:简介与安装 Cobalt Strike系列教程第二章:Beacon详 ...