当前位置:网站首页>很多小伙伴不太了解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五大数据类型与使用场景汇总!!(含完整实战案例,建议收藏)》
好了,今天就到这儿吧,小伙伴们点赞、收藏、评论,一键三连走起呀,我是冰河,我们下期见~~
边栏推荐
- 软件测试笔试题你会吗?
- break net
- QT -- package the program -- don't install qt- you can run it directly
- COMSOL - Construction of micro resistance beam model - final temperature distribution and deformation - establishment of geometric model
- Write a pure handwritten QT Hello World
- What kind of MES system is a good system
- The numerical value of the number of figures thought of by the real-time update of the ranking list
- In depth analysis of ArrayList source code, from the most basic capacity expansion principle, to the magic iterator and fast fail mechanism, you have everything you want!!!
- 用户之声 | 对于GBase 8a数据库学习的感悟
- Working principle of stm32gpio port
猜你喜欢

nmap工具介绍及常用命令

Js中forEach map无法跳出循环问题以及forEach会不会修改原数组

用户之声 | 冬去春来,静待花开 ——浅谈GBase 8a学习感悟

Remote Sensing投稿經驗分享

Voice of users | understanding of gbase 8A database learning

Remote Sensing投稿经验分享

Write a pure handwritten QT Hello World

Nmap tool introduction and common commands

How to fix the slip ring

【目标跟踪】|DiMP: Learning Discriminative Model Prediction for Tracking
随机推荐
[SolidWorks] modify the drawing format
From starfish OS' continued deflationary consumption of SFO, the value of SFO in the long run
什么样的MES系统才是好系统
Coordinate conversion of one-dimensional array and two-dimensional matrix (storage of matrix)
碳刷滑环在发电机中的作用
ANSI / nema- mw- 1000-2020 magnetic iron wire standard Latest original
Qml 字体使用pixelSize来自适应界面
How to realize batch control? MES system gives you the answer
node js 保持长连接
Remote sensing contribution experience sharing
The foreach map in JS cannot jump out of the loop problem and whether foreach will modify the original array
QT -- package the program -- don't install qt- you can run it directly
In depth analysis of ArrayList source code, from the most basic capacity expansion principle, to the magic iterator and fast fail mechanism, you have everything you want!!!
Matlab method is good~
Working principle of stm32gpio port
How to fix the slip ring
burpsuite
Leetcode exercise - Sword finger offer 36 Binary search tree and bidirectional linked list
C语言-Cmake-CMakeLists.txt教程
Plot function drawing of MATLAB