当前位置:网站首页>很多小伙伴不太了解ORM框架的底层原理,这不,冰河带你10分钟手撸一个极简版ORM框架(赶快收藏吧)
很多小伙伴不太了解ORM框架的底层原理,这不,冰河带你10分钟手撸一个极简版ORM框架(赶快收藏吧)
2022-07-08 00:35:00 【冰 河】
大家好,我是冰河~~
最近很多小伙伴对ORM框架的实现很感兴趣,不少读者在冰河的微信上问:冰河,你知道ORM框架是如何实现的吗?比如像MyBatis和Hibernate这种ORM框架,它们是如何实现的呢?
为了能够让小伙伴们更加深刻并且清晰的理解ORM框架的实现原理,冰河决定自己手撸一个极简版的ORM框架,让小伙伴们一看就能够明白什么是ORM框架?ORM框架到底是如何运行的?ORM框架是如何将程序对象与数据库中的数据进行映射的?不过,在正式开始手撸ORM框架之前,我们要先来搞清楚什么是ORM框架。
什么是ORM框架?
ORM全称为:Object Relational Mapping,翻译成中文就是:对象关系映射。也就是说ORM框架就是对象关系映射框架,它通过元数据描述对象与关系映射的细节,ORM框架在运行的时候,可以根据对应与映射之间的关系将数据持久化到数据库中。
其实,从本质上讲,ORM框架主要实现的是程序对象到关系数据库数据的映射。说的直白点:ORM框架就是将实体和实体与实体之间的关系,转化为对应的SQL语句,通过SQL语句操作数据库,将数据持久化到数据库中,并且对数据进行相应的增删改查操作。
最常用的几种ORM框架为:MyBatis、Hibernate和JFinal。
手撸ORM框架
这里,我们模拟的是手撸Hibernate框架实现ORM,小伙伴们也可以模拟其他的ORM框架实现,核心原理都是相通的。如果大家在模拟其他框架手撸实现ORM时,遇到问题的话,都可以私聊我沟通,我看到的话,会第一时间回复大家。
好了,说干就干,我们开始吧。
@Table注解的实现
首先,我们创建一个io.mykit.annotation.jdk.db.provider
Java包,在这个Java包创建一个@Table注解,@Table注解标注在Java类上,表示当前类会被映射到数据库中的哪张数据表上,如下所示。
package io.mykit.annotation.jdk.db.provider;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/** * 自定义Table注解 * @author binghe * */
@Inherited
@Target({
ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Table {
String value() default "";
}
@Column注解的实现
同样的,在io.mykit.annotation.jdk.db.provider
包下创建一个@Column注解,@Column注解标注在类中的字段上,表示当前类中的字段映射到数据表中的哪个字段上,如下所示。
package io.mykit.annotation.jdk.db.provider;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/** * 自定义Column注解 * @author binghe * */
@Inherited
@Target({
ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Column {
String value() default "";
}
看到这里,不管是使用过MyBatis的小伙伴还是使用过Hibernate的小伙伴,应该都会有所体会吧?没错,@Table注解和@Column注解,不管是在MyBatis框架还是Hibernate框架中,都会被使用到。这里,我们在收录极简版ORM框架时,也使用了这两个经典的注解。
创建实体类
在io.mykit.annotation.jdk.db.provider.entity
包下创建实体类User,并且@Table注解和@Column注解会被分别标注在User类上和User类中的字段上,将其映射到数据库中的数据表和数据表中的字段上,如下所示。
package io.mykit.annotation.jdk.db.provider.entity;
import io.mykit.annotation.jdk.db.provider.Column;
import io.mykit.annotation.jdk.db.provider.Table;
/** * 自定义使用注解的实体 * @author binghe * */
@Table("t_user")
public class User implements Serializable{
@Column("id")
private String id;
@Column("name")
private String name;
public User() {
super();
}
public User(String id, String name) {
super();
this.id = id;
this.name = name;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "User [id=" + id + ", name=" + name + "]";
}
}
注解解析类的实现
在io.mykit.annotation.jdk.db.provider.parser
包中创建一个AnnotationParser类,AnnotationParser 类是整个框架的核心,它负责解析标注在实体类上的注解,并且将对应的实体类及其字段信息映射到对应的数据表和字段上,如下所示。
package io.mykit.annotation.jdk.db.provider.parser;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import io.mykit.annotation.jdk.db.provider.Column;
import io.mykit.annotation.jdk.db.provider.Table;
/** * 解析自定义注解 * @author binghe * */
public class AnnotationParser {
/** * 通过注解来组装查询条件,生成查询语句 * @param obj * @return */
public static String assembleSqlFromObj(Object obj) {
Table table = obj.getClass().getAnnotation(Table.class);
StringBuffer sbSql = new StringBuffer();
String tableName = table.value();
sbSql.append("select * from " + tableName + " where 1=1 ");
Field[] fileds = obj.getClass().getDeclaredFields();
for (Field f : fileds) {
String fieldName = f.getName();
String methodName = "get" + fieldName.substring(0, 1).toUpperCase()
+ fieldName.substring(1);
try {
Column column = f.getAnnotation(Column.class);
if (column != null) {
Method method = obj.getClass().getMethod(methodName);
Object v = method.invoke(obj);
if (v != null) {
if (v instanceof String) {
String value = v.toString().trim();
// 判断参数是不是 in 类型参数 1,2,3
if (value.contains(",")) {
//去掉value中的,
String sqlParams = value.replace(",", "").trim();
//value中都是纯数字
if(isNum(sqlParams)){
sbSql.append(" and " + column.value() + " in (" + value + ") ");
}else{
String[] split = value.split(",");
//将value重置为空
value = "";
for(int i = 0; i < split.length - 1; i++){
value += "'"+split[i]+"',";
}
value += "'"+split[split.length - 1]+"'";
sbSql.append(" and " + column.value() + " in (" + value + ") ");
}
} else {
if(value != null && value.length() > 0){
sbSql.append(" and " + column.value() + " like '%" + value + "%' ");
}
}
} else {
sbSql.append(" and " + column.value() + "=" + v.toString() + " ");
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
return sbSql.toString();
}
/** * 检查给定的值是不是 id 类型 1.检查字段名称 2.检查字段值 * * @param target * @return */
public static boolean isNum(String target) {
boolean isNum = false;
if (target.toLowerCase().contains("id")) {
isNum = true;
}
if (target.matches("\\d+")) {
isNum = true;
}
return isNum;
}
}
至此,我们的极简版ORM框架就实现好了,不过实现完还不行,我们还要对其进行测试验证。
测试类的实现
在io.mykit.annotation.jdk.provider
包下创建AnnotationTest 类,用以测试我们实现的极简ORM框架的效果,具体如下所示。
package io.mykit.annotation.jdk.provider;
import org.junit.Test;
import io.mykit.annotation.jdk.db.provider.entity.User;
import io.mykit.annotation.jdk.db.provider.parser.AnnotationParser;
import io.mykit.annotation.jdk.provider.parser.AnnotationProcessor;
/** * 测试自定义注解 * @author binghe * */
public class AnnotationTest {
@Test
public void testDBAnnotation(){
User testDto = new User("123", "34");
User testDto1 = new User("123", "test1");
User testDto2 = new User("", "test1,test2,test3,test4");
String sql = AnnotationParser.assembleSqlFromObj(testDto);
String sql1 = AnnotationParser.assembleSqlFromObj(testDto1);
String sql2 = AnnotationParser.assembleSqlFromObj(testDto2);
System.out.println(sql);
System.out.println(sql1);
System.out.println(sql2);
}
}
运行测试
我们运行AnnotationTest#testDBAnnotation()
方法,命令行会输出如下信息。
select * from t_user where 1=1 and id like '%123%' and name like '%34%'
select * from t_user where 1=1 and id like '%123%' and name like '%test1%'
select * from t_user where 1=1 and name in ('test1','test2','test3','test4')
可以看到,我们在测试程序中,并没有在测试类中传入或者执行任何SQL语句,而是直接创建User类的对象,并调用AnnotationParser#assembleSqlFromObj()
进行解析,并且将对应的实体类对象转换为SQL语句返回。
其实,MyBatis和Hibernate的底层核心原理都是这样的,大家学会了吗?有不懂的地方欢迎私聊我沟通。赶紧打开你的开发环境,手撸个极简版ORM框架吧!!
大家有啥问题可以在下方留言,如果文章对你有点帮助,欢迎转发给更多的小伙伴~~
好了,今天就到这儿吧,我是冰河,我们下期见~~
写在最后
如果你想进大厂,想升职加薪,或者对自己现有的工作比较迷茫,都可以私信我交流,希望我的一些经历能够帮助到大家~~
推荐阅读:
- 《实践出真知:全网最强秒杀系统架构解密,不是所有的秒杀都是秒杀!!》
- 《从零到上亿用户,我是如何一步步优化MySQL数据库的?(建议收藏)》
- 《我用多线程进一步优化了亿级流量电商业务下的海量数据校对系统,性能再次提升了200%!!(全程干货,建议收藏)》
- 《我用多线程优化了亿级流量电商业务下的海量数据校对系统,性能直接提升了200%!!(全程干货,建议收藏)》
- 《我用10张图总结出了这份并发编程最佳学习路线!!(建议收藏)》
- 《高并发场景下一种比读写锁更快的锁,看完我彻底折服了!!(建议收藏)》
- 《全网最全性能优化总结!!(冰河吐血整理,建议收藏)》
- 《三天撸完了MyBatis,各位随便问!!(冰河吐血整理,建议收藏)》
- 《奉劝那些刚参加工作的学弟学妹们:要想进大厂,这些并发编程知识是你必须要掌握的!完整学习路线!!(建议收藏)》
- 《奉劝那些刚参加工作的学弟学妹们:要想进大厂,这些核心技能是你必须要掌握的!完整学习路线!!(建议收藏)》
- 《奉劝那些刚参加工作的学弟学妹们:这些计算机与操作系统基础知识越早知道越好!万字长文太顶了!!(建议收藏)》
- 《我用三天时间开发了一款老少皆宜的国民级游戏,支持播放音乐,现开放完整源代码和注释(建议收藏)!!》
- 《我是全网最硬核的高并发编程作者,CSDN最值得关注的博主,大家同意吗?(建议收藏)》
- 《毕业五年,从月薪3000到年薪百万,我掌握了哪些核心技能?(建议收藏)》
- 《我入侵了隔壁妹子的Wifi,发现。。。(全程实战干货,建议收藏)》
- 《千万不要轻易尝试“熊猫烧香”,这不,我后悔了!》
- 《清明节偷偷训练“熊猫烧香”,结果我的电脑为熊猫“献身了”!》
- 《7.3万字肝爆Java8新特性,我不信你能看完!(建议收藏)》
- 《在业务高峰期拔掉服务器电源是一种怎样的体验?》
- 《全网最全Linux命令总结!!(史上最全,建议收藏)》
- 《用Python写了个工具,完美破解了MySQL!!(建议收藏)》
- 《SimpleDateFormat类到底为啥不是线程安全的?(附六种解决方案,建议收藏)》
- 《MySQL 8中新增的这三大索引,直接让MySQL起飞了,你竟然还不知道!!(建议收藏)》
- 《撸完Spring源码,我开源了这个分布式缓存框架!!(建议收藏)》
- 《亿级流量高并发秒杀系统商品“超卖”了,只因使用的JDK同步容器中存在这两个巨大的坑!!(踩坑实录,建议收藏)》
- 《奉劝那些刚参加工作的学弟学妹们:要想学好并发编程,这些并发容器的坑是你必须要注意的!!(建议收藏)》
- 《公司的报表工具太难用,我三天撸了个Excel工具,运营小姐姐直呼太好用了,现已开源!!(建议收藏)》
- 《奉劝那些刚参加工作的学弟学妹们:要想进大厂,这些并发编程核心技能是你必须要掌握的!!(建议收藏)》
- 《阿里面试官:高并发大流量秒杀系统如何正确的解决库存超卖问题?(建议收藏)》
- 《Redis五大数据类型与使用场景汇总!!(含完整实战案例,建议收藏)》
好了,今天就到这儿吧,小伙伴们点赞、收藏、评论,一键三连走起呀,我是冰河,我们下期见~~
边栏推荐
- 鼠标事件-事件对象
- Summary of log feature selection (based on Tianchi competition)
- Euler Lagrange equation
- 滑环使用如何固定
- Introduction to grpc for cloud native application development
- Apache多个组件漏洞公开(CVE-2022-32533/CVE-2022-33980/CVE-2021-37839)
- Optimization of ecological | Lake Warehouse Integration: gbase 8A MPP + xeos
- 生态 | 湖仓一体的优选:GBase 8a MPP + XEOS
- ClickHouse原理解析与应用实践》读书笔记(8)
- 日志特征选择汇总(基于天池比赛)
猜你喜欢
I don't know. The real interest rate of Huabai installment is so high
Remote Sensing投稿经验分享
从Starfish OS持续对SFO的通缩消耗,长远看SFO的价值
SQLite3 data storage location created by Android
Sword finger offer II 041 Average value of sliding window
Nacos microservice gateway component +swagger2 interface generation
为什么更新了 DNS 记录不生效?
云原生应用开发之 gRPC 入门
[target tracking] |atom
Matlab r2021b installing libsvm
随机推荐
Capability contribution three solutions of gbase were selected into the "financial information innovation ecological laboratory - financial information innovation solutions (the first batch)"
Anaconda3 tutorial on installing and adding Tsinghua image files
Redux使用
用户之声 | 冬去春来,静待花开 ——浅谈GBase 8a学习感悟
List of top ten domestic industrial 3D visual guidance enterprises in 2022
break net
About snake equation (3)
GBASE观察 | 数据泄露频发 信息系统安全应如何守护
The function of carbon brush slip ring in generator
Usage of xcolor color in latex
跨模态语义关联对齐检索-图像文本匹配(Image-Text Matching)
【目标跟踪】|atom
Break algorithm --- map
How to make the conductive slip ring signal better
Kafka connect synchronizes Kafka data to MySQL
MySQL查询为什么没走索引?这篇文章带你全面解析
Tapdata 的 2.0 版 ,开源的 Live Data Platform 现已发布
Introduction to ADB tools
About snake equation (2)
[target tracking] |atom