当前位置: 首页 > 科技观察

10分钟上手极简版ORM框架!

时间:2023-03-11 22:33:32 科技观察

大家好,我是冰河~~最近很多朋友对ORM框架的实现很感兴趣。很多读者在冰河的微信上提问:冰河,你知道ORM框架是怎么实现的吗?比如MyBatis和Hibernte等ORM框架是如何实现的?为了让小伙伴们对ORM框架的实现原理有更深入更清晰的了解,冰河决定自己搭建一个极简版的ORM框架,让小伙伴们看一看就能明白什么是ORM框架?ORM框架是如何工作的?ORM框架如何映射程序对象和数据库中的数据?不过,在正式开始介绍ORM框架之前,我们需要搞清楚什么是ORM框架。什么是ORM框架?ORM的全称是:ObjectRelationalMapping,中文翻译为:ObjectRelationalMapping。也就是说,ORM框架是一个对象-关系映射框架,它通过元数据来描述对象-关系映射的细节。ORM框架在运行时,可以根据对应关系和映射关系将数据持久化到数据库中。其实本质上,ORM框架主要实现了程序对象到关系数据库数据的映射。说白了:ORM框架就是将实体以及实体与实体之间的关系转换成对应的SQL语句,通过SQL语句操作数据库,将数据持久化到数据库中,并进行相应的增删改查,对数据进行修改和查询操作。最常用的ORM框架有:MyBatis、Hibernate和JFinal。手动ORM框架在这里,我们通过Hibernate框架来模拟ORM的实现。小伙伴们也可以模拟其他ORM框架的实现。核心原则是相同的。如果你在模拟其他框架手工实现ORM时遇到问题,可以私聊我进行交流。如果我看到了,我会尽快回复你。好吧,让我们开始吧。@Table注解的实现首先,我们创建一个io.mykit.annotation.jdk.db.providerJava包,并在这个Java包中创建一个@Table注解。@Table注解标注在Java类上,表示当前类将映射到数据库中的哪个数据表上,如下图。packageio.mykit.annotation.jdk.db.provider;importjava.lang.annotation.Documented;importjava.lang.annotation.ElementType;importjava.lang.annotation.Inherited;importjava.lang.annotation.Retention;importjava.lang.annotation。RetentionPolicy;importjava.lang.annotation.Target;/***自定义表注解*@authorbinghe**/@Inherited@Target({ElementType.TYPE})@Retention(RetentionPolicy.RUNTIME)@Documentedpublic@interfaceTable{Stringvalue()default"";}@Column注解的实现同理,在io.mykit.annotation.jdk.db.provider包下创建@Column注解,@Column注解标注在类中的字段上,表示当前类中的字段映射到数据表中的哪个字段,如下图。packageio.mykit.annotation.jdk.db.provider;importjava.lang.annotation.Documented;importjava.lang.annotation.ElementType;importjava.lang.annotation.Inherited;importjava.lang.annotation.Retention;importjava.lang.annotation。RetentionPolicy;importjava.lang.annotation.Target;/***自定义列注解*@authorbinghe**/@Inherited@Target({ElementType.FIELD})@Retention(RetentionPolicy.RUNTIME)@Documentedpublic@interfaceColumn{Stringvalue()default"";}看到这里,不管是用过MyBatis的朋友,还是用过Hibernate的朋友,应该都有点体会了吧?是的,@Table注解和@Column注解,无论是在MyBatis框架还是在Hibernate框架中都会用到。这里,我们在包含极简ORM框架的时候,也用到了这两个经典的注解。创建一个实体类在io.mykit.annotation.jdk.db.provider.entity包下创建一个实体类User,@Table注解和@Column注解会分别注解在User类和User类中的字段上.映射到数据库中的数据表和数据表中的字段,如下图。packageio.mykit.annotation.jdk.db.provider.entity;importio.mykit.annotation.jdk.db.provider.Column;importio.mykit.annotation.jdk.db.provider.Table;/***自定义使用注解实体*@authorbinghe**/@Table("t_user")publicclassUserimplementsSerializable{@Column("id")privateStringid;@Column("name")privateStringname;publicUser(){super();}publicUser(Stringid,Stringname){super();this.id=id;this.name=name;}publicStringgetId(){returnid;}publicvoidsetId(Stringid){this.id=id;}publicStringgetName(){returnname;}publicvoidsetName(Stringname){this.name=name;}@OverridepublicStringtoString(){return"User[id="+id+",name="+name+"]";}}注解解析类的实现在io.mykit.annotation.jdk.db中。provider在.parser包中创建一个AnnotationParser类。AnnotationParser类是整个框架的核心。它负责解析标注在实体类上的注解,并将对应的实体类及其字段信息映射到对应的数据表和字段中,如下所示。packageio.mykit.annotation.jdk.db.provider.parser;importjava.lang.reflect.Field;importjava.lang.reflect.Method;importio.mykit.annotation.jdk.db.provider.Column;importio.mykit.annotation。jdk.db.provider.Table;/***解析自定义注解*@authorbinghe**/publicclassAnnotationParser{/***通过注解组装查询条件生成查询语句*@paramobj*@return*/publicstaticStringassembleSqlFromObj(Objectobj){Tabletable=obj.getClass().getAnnotation(Table.class);StringBuffersbSql=newStringBuffer();StringtableName=table.value();sbSql.append("select*from"+tableName+"where1=1");字段[]字段=obj.getClass().getDeclaredFields();for(Fieldf:fields){StringfieldName=f.getName();StringmethodName="get"+fieldName.substring(0,1).toUpperCase()+fieldName.substring(1);try{Columncolumn=f.getAnnotation(Column.class);if(column!=null){Methodmethod=obj.getClass().getMethod(methodName);Objectv=method.invoke(obj);if(v!=null){if(vinstanceofString){Stringvalue=v.toString().trim();//判断参数是否为类型参数1,2,3if(value.contains(",")){//去掉value,StringsqlParams=value.replace(",","").trim();//value为纯数字if(isNum(sqlParams)){sbSql.append("and"+column.value()+"in("+value+")");}else{String[]split=value.split(",");//重新将值设为空值="";for(inti=0;i0){sbSql.append("and"+column.value()+"like'%"+value+"%'");}}}else{sbSql.append("and"+column.value()+"="+v.toString()+"");}}}}catch(Exceptione){e.printStackTrace();}}returnsbSql.toString();}/***检查给定的值是否为id类型1.检查字段name2.检查字段值**@paramtarget*@return*/publicstaticbooleanisNum(Stringtarget){booleanisNum=false;if(target.toLowerCase().contains("id")){isNum=true;}if(target.matches("\\d+")){isNum=true;}returnisNum;}}至此,我们的极简ORM框架已经实现。但是实现还不够,我们还需要对其进行测试,以验证测试类的实现在io.mykit.annotation.jdk.provider包下创建AnnotationTest类来测试我们实现的极简ORM框架的效果,如跟随秀。packageio.mykit.annotation.jdk.provider;importorg.junit.Test;importio.mykit.annotation.jdk.db.provider.entity.User;importio.mykit.annotation.jdk.db.provider.parser.AnnotationParser;importio。mykit.annotation.jdk.provider.parser.AnnotationProcessor;/***测试自定义注解*@authorbinghe**/publicclassAnnotationTest{@TestpublicvoidtestDBAnnotation(){UsertestDto=newUser("123","34");UsertestDto1=newUser("123","test1");UsertestDto2=newUser("","test1,test2,test3,test4");Stringsql=AnnotationParser.assembleSqlFromObj(testDto);Stringsql1=AnnotationParser.assembleSqlFromObj(testDto1);Stringsql2=AnnotationParser.assembleSqlFromObj(testDto1);Stringsql2=AnnotationParser.assembleSqlFromObj(testDto2);System.out.println(sql);System.out.println(sql1);System.out.println(sql2);}}运行测试我们运行AnnotationTest#testDBAnnotation()方法,命令行会输出如下信息。select*fromt_userwhere1=1andidlike'%123%'andnamelike'%34%'select*fromt_userwhere1=1andidlike'%123%'andnamelike'%test1%'select*fromt_userwhere1=1andnamein('test1','test2','test3','test4')可以看到在测试程序中,我们并没有在测试类中传入或执行任何SQL语句,而是直接创建了User类的对象,调用AnnotationParser#assembleSqlFromObj()进行解析,得到相应的实体类对象转换成SQL语句返回。本文转载自微信公众号“冰河科技”,可通过以下二维码关注。转载本文请联系冰川科技公众号。