手撸一个JdbcTemplate,带你了解其原理
前提要求
- 能够使用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,带你了解其原理相关推荐
- 手撸一个springsecurity,了解一下security原理
今天手撸一个简易版本的springsecurity,带大家理解下springsecurity的原理.转载自:www.javaman.cn 手撸一个springsecurity,了解一下security ...
- java设计模式————模板模式,手撸一个JDBCTemplate
模板模式(Template Method Pattern) 定义一个算法的骨架,并允许子类为一个或者多个步骤提供实现. 模板方法使得子类可以在不改变算法结构的情况下,重新定义算法的某些步骤. 属于行为 ...
- 呆呆带你手撸一个思维导图-基础篇
希沃ENOW大前端 公司官网:CVTE(广州视源股份) 团队:CVTE旗下未来教育希沃软件平台中心enow团队 「本文作者:」 前言 你盼世界,我盼望你无bug.Hello 大家好,我是霖呆呆! 哈哈 ...
- 很多小伙伴不太了解ORM框架的底层原理,这不,冰河带你10分钟手撸一个极简版ORM框架(赶快收藏吧)
大家好,我是冰河~~ 最近很多小伙伴对ORM框架的实现很感兴趣,不少读者在冰河的微信上问:冰河,你知道ORM框架是如何实现的吗?比如像MyBatis和Hibernate这种ORM框架,它们是如何实现的 ...
- .Net Core手撸一个基于Token的权限认证
说明 权限认证是确定用户身份的过程.可确定用户是否有访问资源的权力 今天给大家分享一下类似JWT这种基于token的鉴权机制 基于token的鉴权机制,它不需要在服务端去保留用户的认证信息或者会话信息 ...
- Goroutine 并发调度模型深度解析之手撸一个高性能 goroutine 池
文章目录 1 前言 2 Goroutine & Scheduler 2.1 线程那些事儿 2.1.1 用户级线程模型 2.1.2 内核级线程模型 2.1.3 两级线程模型 2.2 G-P-M ...
- 五分钟,手撸一个Spring容器!
Spring是我们最常用的开源框架,经过多年发展,Spring已经发展成枝繁叶茂的大树,让我们难以窥其全貌. 这节,我们回归Spring的本质,五分钟手撸一个Spring容器,揭开Spring神秘的面 ...
- javascript实现图片轮播_手撸一个简易版轮播图(上)
手撸一个简易版轮播图 实现原理,通过控制 swiper-warpper 容器的定位来达到切换图片的效果. 页面布局 简易版轮播图 < > 页面样式 .container{width: 60 ...
- php 六边形 属性图 能力数值图,详解基于 Canvas 手撸一个六边形能力图
一.前言 六边形能力图如下,由 6 个 六边形组成,每一个顶点代表其在某一方面的能力.这篇文章我们就来看看如何基于 canvas 去绘制这么一个六边形能力图.当然,你也可以基于其他开源的 js 方案来 ...
最新文章
- Go 分布式学习利器(16) -- go中可复用的package构建
- 老弟,你连HTTPS 原理都不懂,还给我讲“中间人攻击”,逗我吗...
- Asp.net MVC 示例项目Suteki.Shop分析之---结束篇
- 【资源】《动手学数据分析》开源教程完整发布!
- 春节期间小游戏同时在线人数最高达2800万人/小时
- QQ浏览器怎么设置主页 QQ浏览器设置默认主页教程
- springmvc重定向到另一个项目_SpringMVC结合Ajax、请求转发重定向、视图解析器
- Libevent源码分析-----日志和错误处理
- 电源大师课笔记 2.9
- 直播软件视频流怎样测试,手把手教你,如何用视频号直播推流!
- linux 查看 java opts,linux查看java opts
- Java StackTraceElement源码总结 StackTraceElement源码注释翻译和解析中英文对照版
- 奖学金——信息学奥赛一本通1179题解
- WSAData小说明(转)
- project02:阶段性总结
- MP4 全介绍【转载】
- 《大数据机器学习实践探索》 ---- 大数据机器学习:spark mlib 库【简介 与 架构初探】
- (USB:VCP+HID复合设备与系统配置)
- 服务器r720按f几重装系统,联想拯救者r720按哪个键进入bios设置
- iOS设备唯一标识符解决方案
热门文章
- java 捕获异常并存入数据库_java异常处理,报异常的话怎么处理对象值,并持久化到数据库中...
- 用python实现杨辉三角的几种不同方式
- 网络安全工具:Wireshark
- 分类问题-样本权重(sample_weight)和类别权重(class_weight)
- tinybert华为
- view(*args)改变张量的大小和形状_pytorch reshape numpy
- npm install遇到ENOENT: no such file or directory, rename错误
- LeetCode简单题之仅执行一次字符串交换能否使两个字符串相等
- MyBatis常规CURD详解及拓展~
- GOF23设计模式(创建型模式) 原型模式