ORM框架

本文介绍了如何手写一个简单的ORM框架,使用了泛型、注解和反射技术,以减少SQL编写。通过创建连接数据库的工具类Dbutil和一个父类BaseDao,实现了无需手动写SQL的单表CRUD操作。BaseDao能根据实体类自动构建并执行SQL,适用于不同表的通用操作。
摘要由CSDN通过智能技术生成

回顾:

反射: 把类中成员抽取为其他类对象的过程。就是反射。

反射类: Class--->实例化类对象。

获取属性类对象: Field

获取方法类对象: Method

获取构造方法类对象: Constructor

概述:

手写ORM框架: O(Object 对象) R(Relative 关系) M(Mapping 映射) 对象关系映射。把数据中的表映射为java中的实体类,表中的一条记录映射为java实体类对象。表中的列映射实体的属性了。

之前我们学习过一个ORM---Mybatis.-----单表的CRUD无需写任何sql语句。

我们自己手写的ORM框架使用的技术: 泛型 注解 反射。

目录:

1.创建maven工程并引入相关依赖

2.创建一个连接数据库的工具类。

3.创建一个父类BaseDao

技术细节:

1.创建maven工程并引入相关依赖

 <dependencies>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.31</version>
        </dependency>
    </dependencies>

2.创建一个连接数据库的工具类。

 代码演示:

jdbc.driverName=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/qy165?serverTimezone=Asia/Shanghai
jdbc.username=root
jdbc.password=123456789

 

 代码演示:

package com.aaa.util;


import java.io.InputStream;
import java.sql.*;
import java.util.Properties;

/**
 * 创建一个连接数据库的工具类
 */

public class Dbutil {
    //硬编码
    private  static String driverName = "";
    private  static String url = "";
    private  static String username = "";
    private  static String password = "";


    static{
        //静态代码块。----随着类的加载而被加载,而且只会被加载一次。
        try {
            //加载属性文件
            InputStream inputStream = ClassLoader.getSystemResourceAsStream("db.properties");
            //属性工具类
            Properties properties = new Properties();
            //加载属性文件
            properties.load(inputStream);
            //获取驱动名称
            driverName = properties.getProperty("jdbc.driverName");
            url = properties.getProperty("jdbc.url");
            username = properties.getProperty("jdbc.username");
            password = properties.getProperty("jdbc.password");
        }catch (Exception e){
            System.out.println("名字为db.properties的属性文件不存在");
            e.printStackTrace();
        }
    }

    /**
     * 获取链接对象
     * @return
     * @throws Exception
     */
    public static Connection getConnection() throws Exception {
        //驱动名称
        Class.forName(driverName);
        //获取链接对象
        Connection connection = DriverManager.getConnection(url, username, password);
        return connection;
    }
    //关闭资源
    public static void closeAll(Connection connection, PreparedStatement ps,ResultSet rs) {
try {
    if (rs!=null) {
        rs.close();
    }
    if (ps!=null) {
        ps.close();
    }
    if(connection!=null) {
        connection.close();
    }
}catch (Exception e) {
    e.printStackTrace();
}


     }

    /**
     *测试是否能够拿到链接对象
     * @param args
     * @throws Exception
     */
    public static void main(String[] args) throws Exception {
        System.out.println(getConnection());
    }
}

3.创建一个父类BaseDao

以后子类DAO继承BaseDao类后,无需再写任何sql语句,而就可以完成单表的crud操作。

比如: StudentDao extends BaseDao DeptDao extends BaseDao.

BaseDao对所有表的CRUD操作都能通用。

代码演示:

package com.aaa.dao;

import com.aaa.annotation.TableField;
import com.aaa.annotation.TableId;
import com.aaa.annotation.TableName;
import com.aaa.util.Dbutil;

import java.lang.reflect.AnnotatedType;
import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.function.DoubleBinaryOperator;

public class BaseDao<T>{

    Class<T> clazz;
    public BaseDao(){
        //获取BaseDao子类的反射类对象
        Class<? extends BaseDao> aClass = this.getClass();
        //获取当前Dao子类的父类的反射类
        ParameterizedType parameterizedType = (ParameterizedType) aClass.getAnnotatedSuperclass();
        //得到泛型的反射类
        Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
        clazz = (Class<T>) actualTypeArguments[0];
        System.out.println(clazz);
    }


    //根据主键查询一条记录
    //sql: select * from 表名 where 主键=值;
    public T selectById(Object id) throws Exception{
        StringBuffer sql=new StringBuffer("select * from ");
        TableName annotation = clazz.getAnnotation(TableName.class);
        String tableName=clazz.getSimpleName();
        if(annotation!=null){
            tableName=annotation.value();
        }
        sql.append(tableName+" where ");
        Field[] fields = clazz.getDeclaredFields();
        for(Field field:fields){
            TableId tableId = field.getAnnotation(TableId.class);
            if(tableId!=null){
                sql.append(tableId.value()+"='"+id+"'");
                continue;
            }
        }
        //执行sql语句
        Connection connection = Dbutil.getConnection();
        PreparedStatement ps=connection.prepareStatement(sql.toString());
        ResultSet rs = ps.executeQuery();
        T t =null;
        while (rs.next()){
            t= clazz.newInstance();
            Field[] declaredFields = clazz.getDeclaredFields();
            for(Field field:declaredFields){
                field.setAccessible(true);
                String name = field.getName();
                TableField tableField = field.getAnnotation(TableField.class);
                TableId tableId = field.getAnnotation(TableId.class);
                if(tableField!=null){
                    name=tableField.value();
                }
                if(tableId!=null){
                    name=tableId.value();
                }
                Object v = rs.getObject(name);
                field.set(t,v);
            }
        }
        return t;

    }


    //通用的删除
    //通用的删除sql语句:delete from 表名 where 主键名=值;
    public int delete(Object id)throws Exception {
        StringBuffer sql = new StringBuffer("delete from");
        TableName annotation = clazz.getAnnotation(TableName.class);
        String tableName = clazz.getSimpleName();
        if (annotation != null){
            tableName  = annotation.value();
        }
        sql.append(tableName +" where ");
        Field[] fields = clazz.getDeclaredFields();
        for (Field field:fields){
            TableId tableId = field.getAnnotation(TableId.class);
            if (tableId!=null){
                sql.append(tableId.value()+"='"+id+"'");
                continue;
            }
        }
        //执行sql语句
        //获取链接对象
        Connection connection = Dbutil.getConnection();
        //拿到PreparedStatement对象
        PreparedStatement ps = connection.prepareStatement(sql.toString());

        int i = ps.executeUpdate();
        return i;
    }




    //通用的添加操作
    //通用的添加sql语句:insert into 表名(列名,列名...) values(值,值...)
    public int insert(T t)throws Exception{
        //拼接的sql语句
        StringBuffer sql = new StringBuffer("insert into ");
        //获取表名,实体类名称就是表名。如果表名和实体类名不一致那可以起一个注解,标记一下表名,表名就是注解里的值
            //根据对象获取Class反射类
        Class<?> aclass = t.getClass();
            //获取反射类上的注解对象
        TableName annotation = aclass.getAnnotation(TableName.class);
        String tableName = "";
            //注解不等于空,表名等于注解值
        if(annotation!= null){
           tableName=annotation.value();
           //如果等于空,表名等于类明,getSimpleName获取反射类类名
        }else{
            tableName=aclass.getSimpleName();
        }
        //拼接的sql语句,把表名拼接到insert into后面
        sql.append(tableName);
            //获取该t实体类所有的属性对象;id name loc
        Field[] declaredFields = aclass.getDeclaredFields();
            //用来放所有的属性名的集合
        ArrayList<String> columns = new ArrayList<>();
            //用来放所有的属性值的集合
        ArrayList<String> values = new ArrayList<>();
            //遍历属性对象
        for (Field field : declaredFields){
            //拿到属性名
            String name = field.getName();

            TableId annotation2 = field.getAnnotation(TableId.class);
            if (annotation2 != null||name.equals("id")){
                continue;
            }
            //如果注解值等于空
            TableField annotation1 = field.getAnnotation(TableField.class);
            //如果注解名称不等于空,那么列名就等于注解名称
            if(annotation1!= null){
                name = annotation1.value();
            }
            field.setAccessible(true);
            //拿到该属性或者列对应的值
            Object o = field.get(t);
            //把属性名添加进去
            columns.add(name);
            //把属性值添加进去;加单引号的目的让任意类型都用字符串类型
            values.add("'"+o+"'");
        }
     String columnNames =  columns.toString().replace("[", "( ").replace("]", " )");
     String columnValues = values.toString().replace("[", "( ").replace("]", " )");
        sql.append(columnNames);
        sql.append("values");
        sql.append(columnValues);

        //执行sql语句
        //获取链接对象
        Connection connection = Dbutil.getConnection();
        //拿到PreparedStatement对象
        PreparedStatement ps = connection.prepareStatement(sql.toString());

        int i = ps.executeUpdate();
        return i;
    }

    //修改方法
    //通用的修改sql语句:update 表名 set 列名=值,列名=值...where 主键名=值;
    public int update(T t)throws Exception {
        StringBuilder sql = new StringBuilder("update ");
        //获取实体类的反射类
        Class<?> aclass = t.getClass();
        //获取反射类上指定的注解对象
        TableName annotation = aclass.getAnnotation(TableName.class);
        String tableName = aclass.getSimpleName();
        if (annotation != null) {
            tableName = annotation.value();
        }
        sql.append(tableName + " set ");
        //获取所有的Field
        Field[] declaredFields = aclass.getDeclaredFields();
        String where = " where ";
        for (Field field : declaredFields) {
            field.setAccessible(true);
            String name = field.getName();
            TableId tableId = field.getAnnotation(TableId.class);
            if (name.equals("id") ) {
                where = where + " id='" + field.get(t)+ "'";
                continue;
            }
            if (tableId!=null) {
                where = where + tableId.value()+"'"+field.get(t)+ "'";
                continue;
            }
            TableField tableField = field.getAnnotation(TableField.class);
            if (tableField != null) {
                name = tableField.value();
            }
            String value = "'" + field.get(t) + "'";
            sql.append(name + " = " + value + ",");
        }
        String sql2 = sql.toString().substring(0, sql.length()-1)+where;

        //执行sql语句
        //获取链接对象
        Connection connection = Dbutil.getConnection();
        //拿到PreparedStatement对象
        PreparedStatement ps = connection.prepareStatement(sql2);

        int i = ps.executeUpdate();
        return i;
    }




}

总结:

 在其他项目中创建lib包,引用即可

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值