Mybatis注解手写源码篇

通过手写模拟Mybatis底层源码实现,了解参数解析底层原理,了解执行SQL底层原理,了解Mybatis结果处理底层原理

目录

启动


public class MyApplication {
    public static void main(String[] args) {
        UserMapper mapper = ProxyFactory.getMapper(UserMapper.class);
        List<User> list = mapper.getUser("root", "123");
        System.out.println(list);

        User user = mapper.getUser(2);
        System.out.println(user);

    }
}

代理工厂类ProxyFactory


package com.example.demo.mybatis;

import com.example.demo.User;

import java.lang.reflect.*;
import java.sql.*;
import java.util.*;

public class ProxyFactory {
    static String url="jdbc:mysql://localhost:3306/springcloud?characterEncoding=utf8";
    static String username="root";
    static String userpwd="123456";
    private static Map<Class,TypeHandler> typeHandlerMap=new HashMap<>();

    static {
        typeHandlerMap.put(String.class,new StringTypeHandler());
        typeHandlerMap.put(Integer.class,new IntegerTypeHandler());

        try {
            Class.forName("com.mysql.cj.jdbc.Driver");
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }

    public static <T> T getMapper(Class<T> mapper){

        Object proxyInstance = Proxy.newProxyInstance(ClassLoader.getSystemClassLoader(), new Class[]{mapper}, new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                Connection connection = DriverManager.getConnection(url, username, userpwd);

                Select annotation = method.getAnnotation(Select.class);
                String value = annotation.value();

                Map<String,Object> map=new HashMap<>();
                //获得方法参数名称存放到map集合中,键为参数名称,值为参数数值
                Parameter[] parameters = method.getParameters();
                for (int i=0;i<parameters.length;i++) {
                    String value1 = parameters[i].getAnnotation(Param.class).value();
                    map.put(value1,args[i]);
                    map.put(parameters[i].getName(),args[i]);
                }

                //Mybatis占位符解析器
                ParameterMappingTokenHandler parameterMappingTokenHandler=new ParameterMappingTokenHandler();
                GenericTokenParser genericTokenParser=new GenericTokenParser("#{","}",parameterMappingTokenHandler);
                String parse = genericTokenParser.parse(value);

                //执行sql语句
                PreparedStatement preparedStatement = connection.prepareStatement(parse);

                //获得sql语句{}内的参数名称
                List<ParameterMapping> parameterMappingList = parameterMappingTokenHandler.getParameterMappingList();
                for (int i=0;i<parameterMappingList.size();i++) {
                    String property = parameterMappingList.get(i).getProperty();
                    Object o = map.get(property);
                    Class<?> type = o.getClass();
                    //根据参数的不同类型执行不同preparedStatement的set方法
                    typeHandlerMap.get(type).setParameter(preparedStatement,i+1,o);
                }

                ResultSet resultSet = preparedStatement.executeQuery();

                //获得方法的返回类型,根据是否是泛型进行判断,获得实体类的Class对象
                Class resultType=null;
                Type genericReturnType = method.getGenericReturnType();
                if(genericReturnType instanceof Class){
                    resultType=(Class)genericReturnType;
                }
                else if(genericReturnType instanceof ParameterizedType){
                    Type[] actualTypeArguments = ((ParameterizedType) genericReturnType).getActualTypeArguments();
                    resultType=(Class) actualTypeArguments[0];
                }
                //获取数据库字段
                ResultSetMetaData metaData = resultSet.getMetaData();
                List<String> list=new ArrayList<>();
                for(int i=0;i<metaData.getColumnCount();i++){
                    list.add(metaData.getColumnName(i+1));
                }

                //将实体类的所有的set方法放到map集合中,键为属性名,值为对应的set方法
                Map<String,Method> methodMap=new HashMap<>();
                for (Method declaredMethod : resultType.getDeclaredMethods()) {
                    if(declaredMethod.getName().startsWith("set")){
                        String substring = declaredMethod.getName().substring(3);
                        substring=substring.substring(0,1).toLowerCase(Locale.ROOT)+substring.substring(1);
                        methodMap.put(substring,declaredMethod);
                    }
                }


                List<Object> resultlist=new ArrayList<>();
                Object result=null;
                while (resultSet.next()){
                    Object instance = resultType.newInstance();//实体类必须有无参构造对象
                    for(int i=0;i<list.size();i++){
                        String column = list.get(i);//数据库字段
                        Method method1 = methodMap.get(column);//获得对应的set方法
                        Class clazz = method1.getParameterTypes()[0];//获得set方法参数
                        TypeHandler typeHandler = typeHandlerMap.get(clazz);
                        method1.invoke(instance,typeHandler.getResult(resultSet,column));
                    }
                    resultlist.add(instance);

                }

                if(method.getReturnType().equals(List.class)){
                    result=resultlist;
                }else {
                    result=resultlist.get(0);
                }

                connection.close();
                return result;

            }
        });
        return (T) proxyInstance;
    };
}

TypeHandler接口


public interface TypeHandler<T> {
    void setParameter(PreparedStatement preparedStatement,int i,T t);

    T getResult(ResultSet resultSet,String columnName);
}

StringTypeHandler


public class StringTypeHandler implements TypeHandler<String>{
    @Override
    public void setParameter(PreparedStatement preparedStatement, int i, String s) {
        try {
            preparedStatement.setString(i,s);
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }
    }

    @Override
    public String getResult(ResultSet resultSet, String columnName) {
        try {
            return resultSet.getString(columnName);
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }
        return null;
    }
}

注:源码下载链接在我的文件资源:https://download.csdn.net/download/qq_43649937/87513406

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
### 回答1: MyBatis-Plus是一个基于MyBatis的增强工具,在MyBatis的基础上提供了更加便捷的CRUD操作、分页查询以及代码生成等功能。下面是MyBatis-Plus源码下载的步骤和方法: 1. 打开MyBatis-Plus的官方网站:https://baomidou.com/ 2. 在网站的首页上方菜单栏找到“Github”选项,点击进入MyBatis-Plus的Github页面。 3. 在Github页面上,可以看到MyBatis-Plus的所有开源代码。点击页面右上方的“Code”按钮,然后选择“Download ZIP”选项进行下载。 4. 下载完成后,将下载的ZIP文件解压到指定的文件夹中。 此外,如果你更希望直接通过Maven等构建工具来引入MyBatis-Plus,也可以在项目的pom.xml文件中添加MyBatis-Plus的依赖,然后通过构建工具自动下载源码。 总之,获取MyBatis-Plus源码最简便的方法是通过其官方网站或Github页面下载。这样就能够获得最新版本MyBatis-Plus源码,方便进行二次开发或查看源码实现细节。 ### 回答2: 要下载MyBatis-Plus源码,可以按照以下步骤进行操作。 1. 打开MyBatis-Plus的GitHub仓库页面。在浏览器中输入"https://github.com/baomidou/mybatis-plus",进入仓库页面。 2. 在仓库页面上,可以看到一个绿色的按钮,上面标有"Code"。点击这个按钮,会出现一个下拉菜单。 3. 在下拉菜单中,选择"Download ZIP"。点击后会自动下载一个ZIP压缩文件到本地电脑。 4. 解压下载的ZIP压缩文件,可以得到MyBatis-Plus的源代码。 此外,也可以通过其他方式获取MyBatis-Plus的源码,比如使用Git命令克隆仓库。你可以在命令行中执行以下命令:git clone https://github.com/baomidou/mybatis-plus.git。这样可以将整个仓库克隆到你的本地电脑上。 下载MyBatis-Plus源码后,你就可以在本地进行修改和扩展。可以使用Java开发工具(如IntelliJ IDEA、Eclipse等)导入源码工程,然后进行编译和运行,进行源码的阅读和修改,以满足你的需求。 希望上述回答对你有所帮助。如有其他问题,请随时提问。 ### 回答3: Mybatis-Plus是一个优秀的Mybatis增强工具,可以在数据库操作中提供更多的便利和增强的功能。如果想要下载Mybatis-Plus的源码,可以按照以下步骤进行操作: 第一步,打开Mybatis-Plus的官方Github仓库,找到源码的下载链接。可以通过搜索引擎输入"mybatis-plus github"来找到官方仓库。 第二步,进入官方仓库后,可以点击 "Clone or download" 按钮,然后选择 "Download ZIP" 选项进行下载。这样就可以将整个Mybatis-Plus源码以zip压缩方式下载到本地。 第三步,下载完成后,可以将zip文件解压到本地的任意目录。 第四步,进入解压后的文件夹,可以看到Mybatis-Plus的源码文件和项目结构。 至此,你已经成功下载了Mybatis-Plus的源码。可以在本地对源码进行查看、学习和调试。 值得注意的是,Mybatis-Plus的源码是基于Java语言编写的,所以需要确保本地环境已经安装了Java开发工具。另外,Mybatis-Plus的源码是一个完整的项目,包含了各种功能模块和依赖库,所以无需额外的配置即可进行使用。 通过下载Mybatis-Plus的源码,可以深入了解其内部实现原理、自定义扩展功能,同时也能更好地理解和使用Mybatis-Plus提供的各种便利和增强功能,对于深入学习和使用Mybatis-Plus都非常有帮助。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

山河亦问安

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值