当前位置:网站首页>Many friends don't know the underlying principle of ORM framework very well. No, glacier will take you 10 minutes to hand roll a minimalist ORM framework (collect it quickly)

Many friends don't know the underlying principle of ORM framework very well. No, glacier will take you 10 minutes to hand roll a minimalist ORM framework (collect it quickly)

2022-07-08 01:55:00 glacier

Hello everyone , I'm glacier ~~

Recently, a lot of little friends are interested in ORM I'm interested in the implementation of the framework , Many readers asked on binghe's wechat : glacier , You know, ORM How is the framework implemented ? Such as MyBatis and Hibernate such ORM frame , How do they come about ?

In order to make friends understand more deeply and clearly ORM Implementation principle of framework , Glacier decided to make a minimalist version of ORM frame , Let's see what it is ORM frame ?ORM How the framework works ?ORM How a framework maps program objects to data in a database ? however , At the beginning of the ceremony ORM Before frame , We need to figure out what is ORM frame .

What is? ORM frame ?

ORM Its full name is :Object Relational Mapping, Translated into Chinese : Object relation mapping . in other words ORM A framework is an object relational mapping framework , It describes the details of object and relation mapping through metadata ,ORM When the framework is running , The data can be persisted to the database according to the relationship between correspondence and mapping .

Actually , essentially ,ORM The framework mainly realizes the mapping from program object to relational database data . Speak straight and white :ORM Framework refers to the relationship between entities and entities , Translate into the corresponding SQL sentence , adopt SQL Statement operation database , Persisting data into a database , And add, delete, modify and query the data accordingly .

The most commonly used ORM The framework is :MyBatis、Hibernate and JFinal.

Hand rolling ORM frame

here , We're simulating hand roll Hibernate Framework implementations ORM, Guys can simulate other things as well ORM Framework implementations , The core principles are interlinked . If you are simulating other frameworks to implement ORM when , In case of problems , You can talk to me in private , If I see it , I will reply to you as soon as possible .

Okay , Do as you say , Let's start .

@Table Implementation of annotations

First , We create a io.mykit.annotation.jdk.db.provider Java package , In this Java Package creates a @Table annotation ,@Table Note on Java Class , Indicates which data table the current class will be mapped to in the database , As shown below .

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;
/** *  Customize Table annotation  * @author binghe * */
@Inherited
@Target({
    ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Table {
    
 String value() default "";
}

@Column Implementation of annotations

alike , stay io.mykit.annotation.jdk.db.provider Create a @Column annotation ,@Column Annotations are marked on fields in the class , Indicates which field in the current class is mapped to in the data table , As shown below .

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;
 
/** *  Customize Column annotation  * @author binghe * */
@Inherited
@Target({
    ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Column {
    
 String value() default "";
}

See here , Whether it's used MyBatis My little friends have used Hibernate Little buddy , I think we'll all have some experience ? you 're right ,@Table Notes and @Column annotation , No matter what MyBatis Frame or Hibernate In the frame , Will be used to . here , We're in the minimalist edition ORM When the framework , These two classic annotations are also used .

Create entity class

stay io.mykit.annotation.jdk.db.provider.entity Create entity classes under the package User, also @Table Notes and @Column The annotations will be marked separately in User Class and User Class , Map it to the data table in the database and the fields in the data table , As shown below .

package io.mykit.annotation.jdk.db.provider.entity;
 
import io.mykit.annotation.jdk.db.provider.Column;
import io.mykit.annotation.jdk.db.provider.Table;
 
/** *  Custom entities that use annotations  * @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 + "]";
 }
 
}

Implementation of annotation parsing class

stay io.mykit.annotation.jdk.db.provider.parser Create a... In the package AnnotationParser class ,AnnotationParser Class is the core of the whole framework , It is responsible for parsing annotations annotated on entity classes , And the corresponding entity class and its field information are mapped to the corresponding data table and field , As shown below .

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;
 
/** *  Parsing custom annotations  * @author binghe * */
public class AnnotationParser {
    
 /** *  Assemble query conditions through annotations , Generate query statements  * @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();
                            //  Judge whether the parameter is correct  in  Type parameter  1,2,3 
                            if (value.contains(",")) {
      
                             // Get rid of value Medium ,
                             String sqlParams = value.replace(",", "").trim();
                             //value It's all pure numbers 
                             if(isNum(sqlParams)){
    
                              sbSql.append(" and " + column.value() + " in (" + value + ") ");  
                             }else{
    
                              String[] split = value.split(",");
                              // take value Reset to empty 
                              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();  
    }  
  
    /** *  Check that the given value is  id  type  1. Check the field name  2. Check field values  * * @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;  
    }  
}

thus , Our minimalist version ORM The framework is implemented , But not yet , We also need to test and verify it .

Test class implementation

stay io.mykit.annotation.jdk.provider Package created under AnnotationTest class , To test our minimalism ORM Effect of frame , The details are as follows .

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;
 
/** *  Test custom annotations  * @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);  
 }
}

Run the test

We run AnnotationTest#testDBAnnotation() Method , The command line will output the following information .

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') 

You can see , We are in the test program , No... Was passed in or executed in the test class SQL sentence , It's about creating User Class object , And call AnnotationParser#assembleSqlFromObj() To analyze , And convert the corresponding entity class object to SQL Statement returns .

Actually ,MyBatis and Hibernate The underlying core principles are all like this , Have you learned ? If you don't understand something, please chat with me . Open up your development environment , A minimalist version ORM Frame bar !!

If you have any questions, please leave a message below , If the article helps you a little , Welcome to forward to more partners ~~

Okay , That's all for today , I'm glacier , See you next time ~~

At the end

If you want to enter a large factory , I want a promotion and a raise , Or I'm confused about my current job , You can communicate with me by private letter , I hope some of my experiences can help you ~~

Recommended reading :

Okay , That's all for today , Like it, guys 、 Collection 、 Comment on , Get up with one button three times in a row , I'm glacier , See you next time ~~

原网站

版权声明
本文为[glacier]所创,转载请带上原文链接,感谢
https://yzsam.com/2022/189/202207080035189820.html