超详细!带你手写一个简单的ORM框架领悟mybatis,hibernate,jpa对象关系映射的秘密

1、ORM介绍
    对象关系映射
    解决了一个问题: 对象模型和关系模型之间阻抗。
    对象模型                     关系模型
    对象名称 Student             表           t_student
    对象属性类型 Integer         列的值的类型 int
    对象属性名称 stuId           列名         student_id
   1、ORM思想就诞生=>Java是一门面向对象的语言。
   2、操作对象中属性的值间接操作数据库中表。
   实现方式:hibernate框架
   Student.hbm.xml


	
		
	
	
   
   
   mybatis框架:
   
		
		
   
   
   // 通过注解方式完成ORM映射配置
   JPA,hibernate,spring-data-jpa
  
   @Table(name="t_student")
   public class Student {
		
		@Id // 映射主键
		@Column(name="student_id")
		private Integer studentId;
		
		@Column(name="student_name")
		private String studentName;
   }


   
   springBoot(mybatis,spring-data-jpa,hibernate)=>微框架
   

2、ORM框架的核心反射
   反射:API
   自定义注解:核心语法和使用方式

3、模拟ORM的框架的部分实现

首先需要连接到JDBC,导入我们的驱动包以及手写一个工具类

手动实现增删改执行返回影响行数的方法

package com.orm.demo.db;

/**
 * @author longhai
 * @date 2018/9/19 - 14:06
 */
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;

/**
 * 操作数据的通过方法
 */
public class DBUtils {
    private static final String DRIVER_CLASS = "com.mysql.jdbc.Driver";
    private static final String URL = "jdbc:mysql://localhost:3306/practice?useSSL=true";
    private static final String USERNAME = "root";
    private static final String PASSWORD = "123456";

    static {
        try {
            Class.forName(DRIVER_CLASS);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }

    /**
     * 获取连接对象的方法
     *
     * @return
     */
    private static Connection getConnection() {
        try {
            return DriverManager.getConnection(URL, USERNAME, PASSWORD);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
    /**
     * 编写一个执行通过的增,删,改的方法, 返回受影响的行数
     */
    public static int executeUpdate(String sql, Object...parameters) {

        try (
                Connection connection = getConnection();
                PreparedStatement pst = connection.prepareStatement(sql);
        ) {
            //在sql语句里面添加所对应的参数
            // 是否设置参数呢
            if (parameters.length > 0 ) {
                for (int i = 0; i < parameters.length; i++) {
                    // 循环设置参数
                    pst.setObject(i + 1, parameters[i]);//注意:此方法在API里面写到,
                    // 第一个参数不是零,是1,所以要i+1
                }
            }

            return pst.executeUpdate();
        } catch (Exception e) {
            e.printStackTrace();
        }

        return 0;
    }

}

然后创建一个学生对象

package com.orm.demo.model;

import com.orm.demo.annoation.Colum;
import com.orm.demo.annoation.Table;

/**
 * @author longhai
 * @date 2018/9/19 - 14:29
 */
@Table("t_student")
public class StudentInfo {
    @Colum("student_id")
    private Integer studentId;
    @Colum("student_name")
    private String studentName;
    @Colum("student_sex")
    private String studentSex;
    @Colum("student_age")
    private int studentAge;

    public StudentInfo(Integer studentId, String studentName, String studentSex, int studentAge) {
        this.studentId = studentId;
        this.studentName = studentName;
        this.studentSex = studentSex;
        this.studentAge = studentAge;
    }

    public Integer getStudentId() {
        return studentId;
    }

    public void setStudentId(Integer studentId) {
        this.studentId = studentId;
    }

    public String getStudentName() {
        return studentName;
    }

    public void setStudentName(String studentName) {
        this.studentName = studentName;
    }

    public String getStudentSex() {
        return studentSex;
    }

    public void setStudentSex(String studentSex) {
        this.studentSex = studentSex;
    }

    public int getStudentAge() {
        return studentAge;
    }

    public void setStudentAge(int studentAge) {
        this.studentAge = studentAge;
    }

}

自定义注解Colum和Table

package com.orm.demo.annoation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * @author longhai
 * @date 2018/9/19 - 13:53
 */
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface Colum {
    String value() default "";//属性映射的字段名称
}
package com.orm.demo.annoation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * @author longhai
 * @date 2018/9/19 - 13:52
 */
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Table {
    String value() default "";//注解映射的表名称
}

具体实现类

注:由于注释比较详细,思路我就不多说了,非常易懂

 

package com.orm.demo;

import com.orm.demo.annoation.Colum;
import com.orm.demo.annoation.Table;
import com.orm.demo.db.DBUtils;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;

/**
 * @author longhai
 * @date 2018/9/19 - 14:36
 *
*
 * javabean操作的通用工具类
 * 
 *     目标: 把entity对象传入到方法中完成该对象的持久化。
 *     核心: 反射
 * 
* */ public class BeanUtil { public static int save(T entity){ // 定义存储SQL语句占位符对应值的集合(也就是属性字段所对应的值) List parameters = new ArrayList<>(); StringBuilder sqlBuilder = new StringBuilder(256);//springbuffer方便组合sql语句 // 获取到当前操作类的Class对象 Class aClass = entity.getClass(); // 问题1: 表名称和类名称不一致怎么办? String tableName = aClass.getSimpleName(); // 判断aClass是否有Table注解 if (aClass.isAnnotationPresent(Table.class)) { Table table = aClass.getAnnotation(Table.class); if (!"".equals(table.value())) { tableName = table.value().toUpperCase();//如果写了别名 // 就将表的名字设为别名的大写 } } // 构建前面半部分SQL sqlBuilder.append("INSERT INTO ").append(tableName).append(" ("); //////////////////////// 确定哪些字段需要参与SQL语句中 ///////////// Field[] fields = aClass.getDeclaredFields(); try {//通过此对象获取到其所有字段以及属性 if (fields != null && fields.length > 0) { for (Field field : fields) { // 获取列名 String columName = field.getName(); //判断是否有表字段和此类属性名称对不上的情况 if (field.isAnnotationPresent(Colum.class)) { Colum column = field.getAnnotation(Colum.class); if (!"".equals(column.value())) { columName = column.value().toUpperCase(); } } // 获取当前这个字段的值 field.setAccessible(true); Object value = field.get(entity); if (value != null) { sqlBuilder.append(columName).append(","); parameters.add(value); //每个字段值追加逗号 } } sqlBuilder.deleteCharAt(sqlBuilder.length() - 1).append(") VALUES ("); //截取最后一个逗号 } } catch (Exception e) { e.printStackTrace(); } for (int i = 0; i < parameters.size(); i++) { sqlBuilder.append("?,"); } //构建sql语句后半段(?,?,?,?, sqlBuilder.deleteCharAt(sqlBuilder.length() - 1).append(")"); //(?,?,?,?) System.out.println(sqlBuilder);//打印sql语句 System.out.println(parameters);//打印参数 return DBUtils.executeUpdate(sqlBuilder.toString(),parameters.toArray()); //由于parameters是集合所以将他toArrary一下 } }
import com.orm.demo.model.StudentInfo;

/**
 * @author longhai
 * @date 2018/9/19 - 14:53
 */
public class TestORM {
    public static void main(String[] args) {
        // 创建一个学生对象
        StudentInfo studentInfo = new StudentInfo(1001, "寒梅", "男", 20);

        int row = BeanUtil.save(studentInfo);

        System.out.println(row > 0 ? "成功" : "失败");
    }
    }

我的数据库是这样的 :表名T_STUDENT 字段:STUDENT_ID,STUDENT_NAME,STUDENT_AGE,STUDENT_SEX

测试一下,我们已经将这一条信息添加到数据库中了!

大家理解了大概的过程了吗? 去动手吧,写出自己想要的功能!框架其实并没有那么困难,要多动手多动脑!

对你有帮助的就点个赞,让天下没有难学的编程

 

 

你可能感兴趣的:(超详细!带你手写一个简单的ORM框架领悟mybatis,hibernate,jpa对象关系映射的秘密)