教你用JAVA注解和反射写一个ORM框架

教你用JAVA注解和反射写一个ORM框架 ,第1张

文章目录
  • 前言
  • 一、ORM框架是什么?
  • 二、讲解
    • 1.创建表和字段的对象映射
    • 2.编写解析类
    • 3.测试
    • 4.持久性保证
  • 总结


前言

做后端项目经常要引入持久层ORM框架,相对于直接 *** 作JDBC来说,利用Mybatis,Hibernate这样的框架能够加快我们的开发进度.引入ORM框架带来的三个好处有:

  • 1.简单 - 避免繁琐的编程语句
    2.精确 -只要对象定义好了,不易出现sql层面的错误
    3.持久性 -避免了频繁写sql带来的连接建立与释放。

下面带大家写一个简易的ORM框架,顺便讲解ORM框架的底层原理(楼主实习面试被问过这个问题/(ㄒoㄒ)/~~)

一、ORM框架是什么?

ORM全称为:Object Relational Mapping对象关系映射,是一种程序对象与数据库中的数据(存储模型和内存模型)的映射,
就是把映射关系以注解的方式放在实体类中,利用反射动态加载类中的对象和方法并生产sql语句,

二、讲解 1.创建表和字段的对象映射

为了对映射关系进行配置,可以用xml 配置的方式,或者是注解的方式,本质都是一样的,表字段过多是建议用xml,但注解讲解起来更加清晰。就是把映射关系以注解的方式放在实体类中,

首先我们创建一个数据库表如下

表名user_table
字段1id
字段2name

然后利用以下两个自定义注解创建表和字段的映射

package DIY_ORM;
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注解
 */
@Inherited
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Table {
 String value() default "";
}
package DIY_ORM;
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注解
 */
@Inherited
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Column {
 String value() default "";
}

然后创建个user类

package DIY_ORM;

//实体类
@Table("user_table")
public class User{
    @Column("id")
    private String id;
    @Column("name")
    private String name;
    
    public User(String id,String name)
    {
        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;
       }
}

以上过程也可以写成xml就是

<hibernate-mapping>
<class name="User" table="user_table">
<id name="id">
<column name="id"/>
</id>
<property name="name">
<column name="name"/>
</property>
</class>
</hibernate-mapping>

可以看到xml文件是更加简洁的。

2.编写解析类

以上过程完成后我们需要创建一个类用于对关系映射进行解析,转换为sql语句,由于事先不知道类名称,故可以用反射实现类的动态加载。

package DIY_ORM;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
 
public class AnnotationParser {
    //利用数据库的实体类对象生成sql语句
    public static String assembleSqlFromObj(Object obj) {  
        Table table = obj.getClass().getAnnotation(Table.class);  //利用反射得到注解
        StringBuffer sbSql = new StringBuffer();  
        String tableName = table.value();  
        //System.out.println("tablename"+tableName);
        sbSql.append("select * from " + tableName + " where 1=1 ");  
        Field[] fileds = obj.getClass().getDeclaredFields();  //利用反射得到类中的对象id,name
        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);  //利用反射执行类的getId,getName方法
                    //System.out.println(method);得到方法名称
                    Object v = method.invoke(obj);   //执行get方法并返回
                    if (v != null) {  
                            sbSql.append(" and " + column.value() + "=" + v.toString() + " ");  
                        }  
                    }  
                }  
             catch (Exception e) {  
                e.printStackTrace();  
            }  
        }  
        return sbSql.toString();  
    }  
}

3.测试

编写个测试函数测试一下,可以看到我们成功的由对象得到了sql语句,接下来调用jdbc执行就行拉。

package DIY_ORM;

public class OrmTest {
    public static void main(String[] args) {
        User testDto = new User("1", "wangwang");  
                String sql = AnnotationParser.assembleSqlFromObj(testDto);  
                System.out.println(sql);  
    }
}

4.持久性保证

以上实现还有一个问题,在成熟的框架中都有selsessionFactory类实现持久化,读取配置类,生产sqlsession,对数据库增删改查,它类似于一个连接池管理类,所以我们还要再写一个连接池,并改写代码。

以下连接池讲解来自作者:乘风破浪的姐姐
链接:https://www.jianshu.com/p/70a4320e5f75

DBCP 是一个开源的连接池,是Apache Common成员之一,在企业开发中也比较常见,tomcat内置的连接池。该数据库连接池既可以与应用服务器整合使用,也可由应用程序独立使用。
应用程序应在系统中增加如下两个 jar 文件:

  1. mysql-connector-java-5.1.37-bin.jar:数据库驱动
  2. commons-dbutils-1.6.jar:提供QueryRunner类方便进行增删改查 *** 作
  3. commons-dbcp-1.4.jar:连接池的实现
  4. commons-pool-1.5.6.jar:连接池实现的依赖库,提供高效的数据库连接池技术
import javax.sql.DataSource;
import org.apache.commons.dbcp.BasicDataSource;
  public class JDBCUtils{
      //创建出BasicDataSource类对象
      private static BasicDataSource datasource = new BasicDataSource();
      //静态代码块,对象BasicDataSource对象中的配置,自定义
      static{
          //数据库连接信息,必须的
          datasource.setDriverClassName("com.mysql.jdbc.Driver");
          datasource.setUrl("jdbc:mysql://localhost:3306/user");
          datasource.setUsername("root");
          datasource.setPassword("123");
          //对象连接池中的连接数量配置,可选的
          datasource.setInitialSize(10);//初始化的连接数
          datasource.setMaxActive(8);//最大连接数量
          datasource.setMaxIdle(5);//最大空闲数
          datasource.setMinIdle(1);//最小空闲
      }
      //定义静态方法,返回BasicDataSource类的对象
      public static DataSource getDataSource(){
          return datasource;
      }
  }
   *  测试写好的工具类,
  import java.sql.SQLException;
  import java.util.List;
  import org.apache.commons.dbutils.QueryRunner;
  import org.apache.commons.dbutils.handlers.ArrayListHandler;
  import cn.itcast.jdbcutils.JDBCUtils;
  public class QueryRunnerDemo{
      public static void main(String[] args) {
          User testDto = new User("1", "wangwang");  
          String sql = AnnotationParser.assembleSqlFromObj(testDto);  
          select(sql);
      }
      //QueryRunner类对象,写在类成员位置
      private static QueryRunner qr = new QueryRunner(JDBCUtils.getDataSource()); 
      //数据表查询
      public static void select(String sql){
          try{
          List<Object[]> list = qr.query(sql, new ArrayListHandler());
          for(Object[] objs : list){
              for(Object obj : objs){
                  System.out.print(obj+"\t");
              }
              System.out.println();
          }
          }catch(SQLException ex){
              throw new RuntimeException("数据查询失败");
          }
      }
  }
总结

以上,DIY_Orm的关键在于:

  1. 利用注解或者xml实现对象关系映射
  2. 利用解析类中的反射实现加载类中的对象和方法,实现sql语句的拼装
  3. 利用数据库连接池实现持久化。
    若有不足,欢迎评论区补充

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/langs/727609.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-04-26
下一篇 2022-04-26

发表评论

登录后才能评论

评论列表(0条)

保存