前提要求

  • 能够使用jdbc链接数据库
  • 能够利用jdbc完成数据库的增删改查等操作
  • 对泛型有一定的了解

基本原理

  • 通过jdbc链接数据库,查询数据库中内容
  • 利用反射对数据库中查询字段进行封装

步骤

1、创建项目

  • 创建Maven工程
  • 输入项目名称
  • 创建resource文件目录:父目录为java文件夹
  • 设置resource文件夹为resource文件夹:单击文件,项目结构

    工程创建到此结束。

2、代码编写

2.1 maven导包,配置pom文件

  • 添加依赖
    mysql依赖、druid连接池依赖
 <!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java --><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.23</version></dependency><!-- https://mvnrepository.com/artifact/com.alibaba/druid --><dependency><groupId>com.alibaba</groupId><artifactId>druid</artifactId><version>1.2.5</version></dependency>

2.2 druid配置

resource文件夹下面创建文件并命名为:druid.properties 名称可以随便
并在文件中添加配置信息:

druid.url=jdbc:mysql://localhost:3306/demo?useUnicode=true&serverTimezone=Asia/Shanghai
druid.driverClassName=com.mysql.cj.jdbc.Driver
druid.username=root
druid.password=123456

根据自己的不同,自行修改

2.3 创建数据库以及表

CREATE DATABASE /*!32312 IF NOT EXISTS*/`demo` /*!40100 DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci */ /*!80016 DEFAULT ENCRYPTION='N' */;USE `demo`;/*Table structure for table `user` */DROP TABLE IF EXISTS `user`;CREATE TABLE `user` (`id` bigint NOT NULL AUTO_INCREMENT,`username` varchar(30) COLLATE utf8mb4_general_ci NOT NULL,`age` int NOT NULL,PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;/*Data for the table `user` */insert  into `user`(`id`,`username`,`age`) values
(1,'张三',20),
(2,'李四',21),
(3,'王五',33),
(4,'陈六',25);

创建之后的数据展示:

2.4 创建数据库对应的Java实体类

import java.util.Objects;public class User {private Long id;private String username;private Integer age;public User() {}public User(Long id, String username, Integer age) {this.id = id;this.username = username;this.age = age;}public Long getId() {return id;}public void setId(Long id) {this.id = id;}public String getUsername() {return username;}public void setUsername(String username) {this.username = username;}public Integer getAge() {return age;}public void setAge(Integer age) {this.age = age;}@Overridepublic boolean equals(Object o) {if (this == o) return true;if (o == null || getClass() != o.getClass()) return false;User user = (User) o;return Objects.equals(id, user.id) && Objects.equals(username, user.username) && Objects.equals(age, user.age);}@Overridepublic int hashCode() {return Objects.hash(id, username, age);}@Overridepublic String toString() {return "User{" +"id=" + id +", username='" + username + '\'' +", age=" + age +'}';}
}

2.5 创建DBUtils


public class DBUtils {private static DataSource dataSource;static {// 配置文件try {InputStream is = App.class.getClassLoader().getResourceAsStream("druid.properties");Properties properties = new Properties();properties.load(is);dataSource = DruidDataSourceFactory.createDataSource(properties);} catch (IllegalArgumentException e) {System.out.println("文件有误");} catch (IOException e) {System.out.println("打开配置文件失败");} catch (Exception e) {System.out.println("德鲁伊数据源创建失败");}}/*** 获取链接** @return 数据库链接*/public static Connection getConnection() {Connection connection = null;try {connection = dataSource.getConnection();} catch (SQLException e) {e.printStackTrace();}return connection;}/*** 资源释放*/public static void release(Connection connection, Statement statement, RowSet rowSet) {try {release(connection, statement, null, rowSet);} catch (SQLException e) {e.printStackTrace();}}public static void release(Connection connection, Statement statement, ResultSet resultSet) {try {release(connection, statement, resultSet, null);} catch (SQLException e) {e.printStackTrace();}}public static void release(Connection connection, Statement statement, ResultSet resultSet, RowSet rowSet) throws SQLException {if (rowSet != null) {rowSet.close();}if (resultSet != null) {resultSet.close();}if (statement != null) {statement.close();}if (connection != null) {connection.close();}}}

2.6 创建JDBCTemplate抽象类

import java.util.List;public abstract class JdbcTemplate<T> {protected Class<T> entityClass;protected JdbcTemplate(Class<T> entityClass) {this.entityClass = entityClass;}public abstract List<T> query(String sql, Object... args);}

2.7 创建QueryTemplate查询模板

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.sql.*;
import java.util.*;public class QueryTemplate<T> extends JdbcTemplate<T> {public QueryTemplate(Class<T> entityClass) {super(entityClass);}@Overridepublic List<T> query(String sql, Object... args) {Connection connection = null;PreparedStatement preparedStatement = null;ResultSet resultSet = null;List<T> result = new ArrayList<>();try {connection = DBUtils.getConnection();preparedStatement = connection.prepareStatement(sql);// 设置参数for (int i = 1; i <= args.length; i++) {setValue(i, args[i - 1], preparedStatement);}resultSet = preparedStatement.executeQuery();Map<String, String> metaMap = getMetaMap(preparedStatement);while (resultSet.next()) {T entity = getEntity(preparedStatement, resultSet);result.add(entity);}} catch (Exception e) {e.printStackTrace();} finally {DBUtils.release(connection, preparedStatement, resultSet);}return result;}/*** 获得具体的对象,并赋值*/private T getEntity(PreparedStatement preparedStatement, ResultSet resultSet) {Map<String, String> metaMap = getMetaMap(preparedStatement);try {T object = entityClass.newInstance();Set<String> keySet = metaMap.keySet();for (String key : keySet) {Object value = getValue(key, metaMap.get(key), resultSet);// 获取属性Field field = entityClass.getDeclaredField(key);Method declaredMethod = entityClass.getMethod(constructSetMethod(key), field.getType());declaredMethod.invoke(object, value);}return object;} catch (Exception e) {e.printStackTrace();}return null;}/*** 获得数据库中 字段名称与数据类型的映射* @return Map*/private static Map<String, String> getMetaMap(PreparedStatement preparedStatement) {Map<String, String> metaMap = new HashMap<>();try {ResultSetMetaData metaData = preparedStatement.getMetaData();// 遍历元素for (int i = 1; i <= metaData.getColumnCount(); i++) {String columnName = metaData.getColumnName(i);String columnTypeName = metaData.getColumnTypeName(i);metaMap.put(columnName, columnTypeName);}} catch (SQLException e) {e.printStackTrace();}return metaMap;}/*** 根据具体字段获得其属性赋值方法* @param key 成员名称* @return 方法名称*/private static String constructSetMethod(String key) {String substring = key.substring(0, 1).toUpperCase() + key.substring(1);return "set" + substring;}/*** 预编译statement赋值* @param index 参数占位符 索引* @param value 具体值*/private static void setValue(int index, Object value, PreparedStatement preparedStatement) {// 获得类型String typeName = value.getClass().getTypeName();try {switch (typeName) {case "java.lang.Long":preparedStatement.setLong(index, Long.parseLong(value.toString()));break;case "java.lang.String":preparedStatement.setString(index, value.toString());break;case "java.lang.Integer":preparedStatement.setInt(index, Integer.parseInt(value.toString()));break;}} catch (SQLException e) {e.printStackTrace();}}/*** 从ResultSet中获取对应的值* @param key 字段* @param typeName 返回数据类型* @param resultSet 结果集* @return 值*/private static Object getValue(String key, String typeName, ResultSet resultSet) {Object value = null;try {switch (typeName) {case "BIGINT":value = resultSet.getLong(key);break;case "INT":value = resultSet.getInt(key);break;case "VARCHAR":value = resultSet.getString(key);break;}} catch (SQLException e) {e.printStackTrace();}return value;}}

创建程序入口类App

public class App {public static void main(String[] args) {JdbcTemplate<User> jdbcTemplate= new QueryTemplate<>(User.class);// 定义sql语句String sql = "select * from user where age > 20";// 执行List<User> users = jdbcTemplate.query(sql);for (User user : users) {System.out.println(user);}}
}

运行结果:

总结: 通过这段代码,基本上就能够知道如何去封装一个数据集,这也是ORM框架的基本封装思路,主要是数据查询比较麻烦,数据封装较为繁琐,其他的方法可以入法炮制,这里不再演示。读者也可以自行测试其他类,或者完成其他操作的封装。

项目Gitee地址

手撸一个JdbcTemplate,带你了解其原理相关推荐

  1. 手撸一个springsecurity,了解一下security原理

    今天手撸一个简易版本的springsecurity,带大家理解下springsecurity的原理.转载自:www.javaman.cn 手撸一个springsecurity,了解一下security ...

  2. java设计模式————模板模式,手撸一个JDBCTemplate

    模板模式(Template Method Pattern) 定义一个算法的骨架,并允许子类为一个或者多个步骤提供实现. 模板方法使得子类可以在不改变算法结构的情况下,重新定义算法的某些步骤. 属于行为 ...

  3. 呆呆带你手撸一个思维导图-基础篇

    希沃ENOW大前端 公司官网:CVTE(广州视源股份) 团队:CVTE旗下未来教育希沃软件平台中心enow团队 「本文作者:」 前言 你盼世界,我盼望你无bug.Hello 大家好,我是霖呆呆! 哈哈 ...

  4. 很多小伙伴不太了解ORM框架的底层原理,这不,冰河带你10分钟手撸一个极简版ORM框架(赶快收藏吧)

    大家好,我是冰河~~ 最近很多小伙伴对ORM框架的实现很感兴趣,不少读者在冰河的微信上问:冰河,你知道ORM框架是如何实现的吗?比如像MyBatis和Hibernate这种ORM框架,它们是如何实现的 ...

  5. .Net Core手撸一个基于Token的权限认证

    说明 权限认证是确定用户身份的过程.可确定用户是否有访问资源的权力 今天给大家分享一下类似JWT这种基于token的鉴权机制 基于token的鉴权机制,它不需要在服务端去保留用户的认证信息或者会话信息 ...

  6. Goroutine 并发调度模型深度解析之手撸一个高性能 goroutine 池

    文章目录 1 前言 2 Goroutine & Scheduler 2.1 线程那些事儿 2.1.1 用户级线程模型 2.1.2 内核级线程模型 2.1.3 两级线程模型 2.2 G-P-M ...

  7. 五分钟,手撸一个Spring容器!

    Spring是我们最常用的开源框架,经过多年发展,Spring已经发展成枝繁叶茂的大树,让我们难以窥其全貌. 这节,我们回归Spring的本质,五分钟手撸一个Spring容器,揭开Spring神秘的面 ...

  8. javascript实现图片轮播_手撸一个简易版轮播图(上)

    手撸一个简易版轮播图 实现原理,通过控制 swiper-warpper 容器的定位来达到切换图片的效果. 页面布局 简易版轮播图 < > 页面样式 .container{width: 60 ...

  9. php 六边形 属性图 能力数值图,详解基于 Canvas 手撸一个六边形能力图

    一.前言 六边形能力图如下,由 6 个 六边形组成,每一个顶点代表其在某一方面的能力.这篇文章我们就来看看如何基于 canvas 去绘制这么一个六边形能力图.当然,你也可以基于其他开源的 js 方案来 ...

最新文章

  1. Android 的权限级别小记
  2. 【直播】今晚(7月1日)京东直播,如何学会深度学习模型设计和优化
  3. 清单文件中android support,Android FileProvider 配置
  4. 北斗信号服务器解算,GPS/北斗定位解算算法的研究
  5. Retrofit2源码解析——网络调用流程(下)
  6. Visio工具 UML的建模
  7. 全排列算法解析(视频+详解+代码+STL)
  8. Qt工作笔记-多线程时间服务应用
  9. Linux : rz、sz命令-从本地拷贝文件到服务器
  10. 线上CPU100%?看看这篇是怎么排查的!
  11. markdown引入代码_给你自己的博客加个 Markdown
  12. python flask接收图像
  13. arm汇编—str,mov等指令
  14. (ExcelVBA编程入门范例)
  15. 【CSS】文字超过三行显示省略号...
  16. 微信公众平台万能代码详解-php语言(二)
  17. 昆石VOS3000/VOS2009 2.1.6.00 操作指南相关
  18. 怎样使用计算机的桌面助手,360桌面助手怎么用
  19. Ubuntu16.04安装qq和微信(亲测 可用)附安装包下载链接
  20. 20135323符运锦期中总结----Linux系统的理解及学习心得

热门文章

  1. 端口映射问题:Bad Request This combination of host and port requires TLS.
  2. 2021-2027年中国透明熔融石英管行业市场全景调查及投资前景分析报告
  3. 2022-2028年中国乙酸钴行业发展现状调研及市场前景规划报告
  4. 2022-2028年中国金融安防行业深度调研及投资前景预测报告
  5. 那些年值得铭记的时刻
  6. Linux下 C语言统计时间差
  7. pytorch中的transpose()
  8. PyTorch在NLP任务中使用预训练词向量
  9. LeetCode简单题之旋转字符串
  10. MegEngine亚线性显存优化