之前写的一个自己实现一个简单的mybatis但是不想写文档了。。。。。

前言

暑假小学期要完了,作业是用Java实现对MySQL的CUDR,不让用Mybatis。

经过努力奋战之后········

我把以前做的改了个名交了,然后脑子一抽,不让用mybatis,那我自己写一个拿来用没问题吧。

经过广泛参考网上的教程,已经实现的简单的注解查询,其他还在慢慢磨

主要参考了这几个大佬的博客

浅析MyBatis(二):手写一个自己的MyBatis简单框架 - Chiakiiii - 博客园 (cnblogs.com)

自己实现一个 MyBatis 框架 - 当年明月123 - 博客园 (cnblogs.com)

还有mybatis中文网 MyBatis的工作原理以及核心流程介绍 - MyBatis中文官网

建议去看这两个大佬的博客

我一开始只是简单写了一个流程理顺一下思路

后来想着,写都写了,就发出来吧,真要学习或者参考建议去大佬的博客,页面比我的好看,代码写的比我好,说的还比我清楚

我是废物,唉

Mybatis的核心流程(这里来源mybatis中文网)

流程图

执行流程图

流程详解

mybatis中文网的解释

(1)读取MyBatis的配置文件。mybatis-config.xml为MyBatis的全局配置文件,用于配置数据库连接信息。

(2)加载映射文件。映射文件即SQL映射文件,该文件中配置了操作数据库的SQL语句,需要在MyBatis配置文件mybatis-config.xml中加载。mybatis-config.xml 文件可以加载多个映射文件,每个文件对应数据库中的一张表。

(3)构造会话工厂。通过MyBatis的环境配置信息构建会话工厂SqlSessionFactory。

(4)创建会话对象。由会话工厂创建SqlSession对象,该对象中包含了执行SQL语句的所有方法。

(5)Executor执行器。MyBatis底层定义了一个Executor接口来操作数据库,它将根据SqlSession传递的参数动态地生成需要执行的SQL语句,同时负责查询缓存的维护。

(6)MappedStatement对象。在Executor接口的执行方法中有一个MappedStatement类型的参数,该参数是对映射信息的封装,用于存储要映射的SQL语句的id、参数等信息。

(7)输入参数映射。输入参数类型可以是Map、List等集合类型,也可以是基本数据类型和POJO类型。输入参数映射过程类似于JDBC对preparedStatement对象设置参数的过程。

(8)输出结果映射。输出结果类型可以是Map、List等集合类型,也可以是基本数据类型和POJO类型。输出结果映射过程类似于JDBC对结果集的解析过程。

我的理解

读取资源文件 对应 1、2

读取连接数据库的配置文件、还有有sql语句的mapper.xml或者mapper.Java等资源配置文件

反应在我写的代码里就是在这一步的时候,连接数据库用的账户、密码url等还有各个mapper的sql语句对应的返回参数的类型已经存储在了一个名为Configuration的对象中

建立与数据库的连接 对应 3

通过Configuration对象中的配置信息建立一个与数据库的连接

应该是创建mapper对象(Mapper mapper = <>)

代码实现

依赖

	 <dependency>
           <groupId>mysql</groupId>
           <artifactId>mysql-connector-java</artifactId>
           <version>8.0.25</version>
       </dependency>
       <!-- https://mvnrepository.com/artifact/com.alibaba/fastjson -->
       <dependency>
           <groupId>com.alibaba</groupId>
           <artifactId>fastjson</artifactId>
           <version>1.2.76</version>
       </dependency>
        <!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.12</version>
            <scope>provided</scope>
        </dependency>

两个pojo类

MappedStatement

这里我偷懒使用了lombok,其实应该是没有params这个的,但限于我对Java的了解,不知道怎么处理多个参数,就加了一个

import lombok.Data;

@Data
public class MappedStatement {
    //sql语句
    private String queryStr;
    
    //返回类型
    private String resultType;
    
    //参数(我自己加的)
    private String params[];
}

Configuration

import lombok.Data;

import java.util.HashMap;
import java.util.Map;

@Data
public class Configuration {
    //数据库驱动
    private String driver;
    
    //数据库链接
    private String url;
    
    //用户名
    private String username;
    
    //密码
    private String password;
    
    //所有的mapper文件内的sql语句以及对应函数等
    private Map<String, MappedStatement>mappers=new HashMap<>();
}

第一步读取资源文件

数据库配置文件

这里我用的是json格式,因为我xml基本没有怎么用过,所以使用的json格式

这里的格式自己怎么喜欢怎么来就行,反正最后都是对应到Configuration这个类

config.json

这里的命名非必须的记得与自己对应就行

{
  "propertyElement": {
    "user":"xxxx",
    "password":"xxxx",
    "driverClass":"xxxx",
    "jdbcUrl":"xxxx"
  },
  "mapperElement": [
    {"class": "com.test.Mapper"},
    {"class": "mapper文件的地址"}
  ]
}

返回Configuration对象

这里用到了两个函数

parse函数是用来读取json文件返回数据库配置的

parseMapperAnnotation函数是读取mapper文件(我写的代码只支持注解,不支持xml文件)

​ 返回的是 Map<String, MappedStatement>mappers

当然还有一个额外的用来读取参数的getMethodParameterNamesByAnnotation

ConfigBuilder

import Mymybatis.cudr.*;
import Mymybatis.pojo.Configuration;
import Mymybatis.pojo.MappedStatement;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;

import java.io.*;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.HashMap;
import java.util.Map;

public class ConfigBuilder {

    /**
     * 读取数据库配置文件
     *
     * @param inputStream json文件的文件流
     * @return configuration对象
     */
    public static Configuration parse(InputStream inputStream) throws ClassNotFoundException {
        String jsonStr = "";
        try {
            Reader reader = new InputStreamReader(inputStream,"utf-8");
            int ch = 0;
            StringBuffer sb = new StringBuffer();
            while ((ch = reader.read()) != -1) {
                sb.append((char) ch);
            }
            reader.close();
            jsonStr = sb.toString();
        } catch (IOException e) {
            e.printStackTrace();
        }
        
        
        JSONObject jsonObject = JSON.parseObject(jsonStr);
        JSONObject configObject = JSON.parseObject(jsonObject.getString("propertyElement"));

        Configuration configuration = new Configuration();
        configuration.setUsername(configObject.getString("user"));
        configuration.setPassword(configObject.getString("password"));
        configuration.setUrl(configObject.getString("jdbcUrl"));
        configuration.setDriver(configObject.getString("driverClass"));

        
        JSONArray mappers =JSON.parseArray(jsonObject.getString("mapperElement"));
        for (int i = 0; i < mappers.size(); i++) {
            JSONObject mapperobject = (JSONObject) mappers.get(i);
            Map<String, MappedStatement>map=parseMapperAnnotation(mapperobject.getString("class"));
            configuration.setMappers(map);
        }
        
        
        return configuration;
    }

    /**
     * 获取指定方法的参数名
     *
     * @param method 要获取参数名的方法
     * @return 按参数顺序排列的参数名列表
     */
    public static String[] getMethodParameterNamesByAnnotation(Method method) {
        Annotation[][] parameterAnnotations = method.getParameterAnnotations();
        if (parameterAnnotations == null || parameterAnnotations.length == 0) {
            return null;
        }
        String[] parameterNames = new String[parameterAnnotations.length];
        int i = 0;
        for (Annotation[] parameterAnnotation : parameterAnnotations) {
            for (Annotation annotation : parameterAnnotation) {
                if (annotation instanceof Param) {
                    Param param = (Param) annotation;
                    parameterNames[i++] = param.value();
                }
            }
        }
        return parameterNames;
    }


    /**
     * 读取mapper文件封装成集合
     *
     * @param mapperClassPath mapper文件的路径
     * @return Map<String, MappedStatement>mappers
     *              String -> mapper文件名+‘.’+函数名
     *              MappedStatement 对应sql语句+返回类型+参数
     */
    private static Map<String, MappedStatement>parseMapperAnnotation(String mapperClassPath) throws ClassNotFoundException {
        Map<String,MappedStatement>mappers =new HashMap<>();
        //获取mapper接口对应的class对象
        Class<?> mapperclass =Class.forName(mapperClassPath);
        //获取class对象中的函数
        Method[] methods = mapperclass.getMethods();
        
        //遍历Method数组对相关注解进行解析
        for (Method method : methods) {
            if (method.isAnnotationPresent(Insert.class)){
                MappedStatement mappedStatement=new MappedStatement();
                Insert insertAnnotation = method.getAnnotation(Insert.class);
                
                //获取参数+设置参数
           		mappedStatement.setParams(getMethodParameterNamesByAnnotation(method));
                
                //获取注解中的value,也就是中的@Insert("sql语句这一部分")
                String queryString = insertAnnotation.value();
                mappedStatement.setQueryStr(queryString);
                
                //获取当前函数的返回值以及泛型
                Type type = method.getGenericReturnType();
                //校验
                if (type instanceof ParameterizedType){
                    ParameterizedType parameterizedType = (ParameterizedType) type;
                    Type[]types=parameterizedType.getActualTypeArguments();
                    Class<?>clazz= (Class<?>) types[0];
                    String resultType=clazz.getName();
                    mappedStatement.setResultType(resultType);
                }
                //给key赋值 Map<String,MapperStatement>mappers
                String methodName = method.getName();
                String className = method.getDeclaringClass().getName();
                String key = className+"."+methodName;
                mappers.put(key,mappedStatement);
            }

            if (method.isAnnotationPresent(Select.class)){
                MappedStatement mappedStatement=new MappedStatement();
                Select selectAnnotation = method.getAnnotation(Select.class);
                mappedStatement.setParams(getMethodParameterNamesByAnnotation(method));
                String queryString = selectAnnotation.value();
                mappedStatement.setQueryStr(queryString);
                Type type = method.getGenericReturnType();
                if (type instanceof ParameterizedType){
                    ParameterizedType parameterizedType = (ParameterizedType) type;
                    Type[]types=parameterizedType.getActualTypeArguments();
                    Class<?>clazz= (Class<?>) types[0];
                    String resultType=clazz.getName();
                    mappedStatement.setResultType(resultType);
                }
                String methodName = method.getName();
                String className = method.getDeclaringClass().getName();
                String key = className+"."+methodName;
                mappers.put(key,mappedStatement);
            }

            if (method.isAnnotationPresent(Delete.class)){
                MappedStatement mappedStatement=new MappedStatement();
                Delete deleteAnnotation = method.getAnnotation(Delete.class);
                mappedStatement.setParams(getMethodParameterNamesByAnnotation(method));
                String queryString = deleteAnnotation.value();
                mappedStatement.setQueryStr(queryString);
                Type type = method.getGenericReturnType();
                if (type instanceof ParameterizedType){
                    ParameterizedType parameterizedType = (ParameterizedType) type;
                    Type[]types=parameterizedType.getActualTypeArguments();
                    Class<?>clazz= (Class<?>) types[0];
                    String resultType=clazz.getName();
                    mappedStatement.setResultType(resultType);
                }
                String methodName = method.getName();
                String className = method.getDeclaringClass().getName();
                String key = className+"."+methodName;
                mappers.put(key,mappedStatement);
            }

            if (method.isAnnotationPresent(Update.class)){
                MappedStatement mappedStatement=new MappedStatement();
                Update updateAnnotation = method.getAnnotation(Update.class);
                mappedStatement.setParams(getMethodParameterNamesByAnnotation(method));
                String queryString = updateAnnotation.value();
                mappedStatement.setQueryStr(queryString);
                Type type = method.getGenericReturnType();
                if (type instanceof ParameterizedType){
                    ParameterizedType parameterizedType = (ParameterizedType) type;
                    Type[]types=parameterizedType.getActualTypeArguments();
                    Class<?>clazz= (Class<?>) types[0];
                    String resultType=clazz.getName();
                    mappedStatement.setResultType(resultType);
                }
                String methodName = method.getName();
                String className = method.getDeclaringClass().getName();
                String key = className+"."+methodName;
                mappers.put(key,mappedStatement);
            }
        }
        return mappers;
    }

    public static void main(String[] args) throws ClassNotFoundException {
       // parse();
    }
}

我写的源码链接

我记得当时写完测试是可以用的
https://gitee.com/october_Wr/study-notes/tree/master/一些备份/MyMybatis/Mymybatis

posted @ 2021-12-24 23:52  tifaIsMyWife  阅读(85)  评论(0)    收藏  举报