当前位置:网站首页>很多小夥伴不太了解ORM框架的底層原理,這不,冰河帶你10分鐘手擼一個極簡版ORM框架(趕快收藏吧)
很多小夥伴不太了解ORM框架的底層原理,這不,冰河帶你10分鐘手擼一個極簡版ORM框架(趕快收藏吧)
2022-07-08 01:55: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五大數據類型與使用場景匯總!!(含完整實戰案例,建議收藏)》
好了,今天就到這兒吧,小夥伴們點贊、收藏、評論,一鍵三連走起呀,我是冰河,我們下期見~~
边栏推荐
- ANSI / NEMA- MW- 1000-2020 磁铁线标准。. 最新原版
- Usage of hydraulic rotary joint
- Keras深度学习实战——基于Inception v3实现性别分类
- 用户之声 | 冬去春来,静待花开 ——浅谈GBase 8a学习感悟
- 云原生应用开发之 gRPC 入门
- 【目标跟踪】|DiMP: Learning Discriminative Model Prediction for Tracking
- How to realize batch control? MES system gives you the answer
- Sum of submatrix
- 子矩阵的和
- 腾讯游戏客户端开发面试 (Unity + Cocos) 双重轰炸 社招6轮面试
猜你喜欢
Voice of users | understanding of gbase 8A database learning
ANSI / NEMA- MW- 1000-2020 磁铁线标准。. 最新原版
微信小程序uniapp页面无法跳转:“navigateTo:fail can not navigateTo a tabbar page“
Matlab r2021b installing libsvm
C语言-模块化-Clion(静态库,动态库)使用
快手小程序担保支付php源码封装
[SolidWorks] modify the drawing format
Apache多个组件漏洞公开(CVE-2022-32533/CVE-2022-33980/CVE-2021-37839)
C语言-Cmake-CMakeLists.txt教程
Exit of processes and threads
随机推荐
Kafka connect synchronizes Kafka data to MySQL
How to realize batch control? MES system gives you the answer
ClickHouse原理解析与应用实践》读书笔记(8)
微信小程序uniapp页面无法跳转:“navigateTo:fail can not navigateTo a tabbar page“
Apache多个组件漏洞公开(CVE-2022-32533/CVE-2022-33980/CVE-2021-37839)
Redux使用
How mysql/mariadb generates core files
[error] error loading H5 weight attributeerror: 'STR' object has no attribute 'decode‘
给刚入门或者准备转行网络工程师的朋友一些建议
Why did MySQL query not go to the index? This article will give you a comprehensive analysis
mysql/mariadb怎样生成core文件
pb9.0 insert ole control 错误的修复工具
快速熟知XML解析
nacos-微服务网关Gateway组件 +Swagger2接口生成
PB9.0 insert OLE control error repair tool
Tencent game client development interview (unity + cocos) double bombing social recruitment 6 rounds of interviews
软件测试笔试题你会吗?
burpsuite
cv2-drawline
uniapp一键复制功能效果demo(整理)