SSM源码分析之Mybatis04-MyBatis源码解读与1.0版本设计过程

Mybatis源码分析04-MyBatis源码解读与1.0版本设计过程

    • 前言
    • 源码解读
    • 1.0版本的设计过程
    • MybatisV1.0手写
    • 后记

前言

上一节,我们debug了mybatis的orm执行过程,这一节我们将核心实现手写成一个demo,暂且称之为MybatisV1.0

源码解读

上一节分析了通过使用mybatis操作数据库的核心流程。
我们画一个图:
SSM源码分析之Mybatis04-MyBatis源码解读与1.0版本设计过程_第1张图片

1.0版本的设计过程

1.0 定义基本功能,定义scope

实际上三个核心类即可:
SSM源码分析之Mybatis04-MyBatis源码解读与1.0版本设计过程_第2张图片
TestMapper --> TestMapper.xml
本质功能就是创建sqlsession会话,找到sql。
SSM源码分析之Mybatis04-MyBatis源码解读与1.0版本设计过程_第3张图片

MybatisV1.0手写

经过以上的分析,我们不难得出结论,mybatis通过sqlsession,以及configuration和Executor作为核心实现完成对于数据库的orm操作。
我们在sqlsession这里处理两件事情:

1. sqlSession.getMapper
	解析Mapper.xml,获取namespace,methodName以及sql语句!
	并将sql语句以map的形式存储
	将当前的要执行的Mapper.class与namespace配对
	成功则从map中通过methodName拿到sql!
2. sqlSession.selectList(selectOne)
	委派模式,sqlSession.selectOne通过Executor.query()真正执行sql
	模板模式,jdbc数据通过类加载器获取用户名密码数据库连接以及sql语句和参数

现在我们先做一个sqlsession类:

public class GPSqlSession {

    private GPConfiguration configuration;
    
    private GPExecutor executor;

    public GPSqlSession(GPConfiguration configuration, GPExecutor executor) {
        this.configuration = configuration;
        this.executor = executor;
    }

   /**
     * 
     * @param clazz 被代理的Mapper
     * @param  
     * @return
     */
    public <T> T getMapper(Class<T> clazz){
        return configuration.getMapper(clazz,this);
    }

    /**
     *
     * @param statement sql 语句
     * @param parameter sql 参数
     * @param 
     * @return
     */
    public <T> T selectOne(String statement,String parameter){
        return executor.query(statement,parameter);
    }
}

configuration类:

public class GPConfiguration {
    public <T> T getMapper(Class<T> clazz,GPSqlSession sqlSession) {
        return (T) Proxy.newProxyInstance(this.getClass().getClassLoader(),
                new Class[]{clazz},
                new GPMapperProxy(sqlSession));
    }

    /**
     * 1、xml解析
     * 2、赋值
     */
    static class TestMapperXml{
        public static final String namespace= "com.xxx.mybatis.v1.TestMapper";

        public static final Map<String,String> methodSqlMapping = new HashMap<>();

        static {
            methodSqlMapping.put("selectByPrimaryKey", "select * from test where id = %d");
        }

    }
}

Executor:

public interface GPExecutor {

    /**
     * query
     * @param statement sql 语句
     * @param parameter sql 参数
     * @param 
     * @return
     */
    <T> T query(String statement, String parameter);
}

ExecutorImpl:

public class GPSimpleExecutor implements GPExecutor{
    @Override
    public <T> T query(String statement, String parameter) {
        Connection connection = null;
        PreparedStatement preparedStatement = null;
        Test test = null;
        try {
            Class.forName("com.mysql.jdbc.Driver");
            connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/gp?useUnicode=true&characterEncoding=utf-8&useSSL=false&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=UTC", "root", "123456");
            preparedStatement = connection.prepareStatement(String.format(statement,Integer.parseInt(parameter)));
            ResultSet rs = preparedStatement.executeQuery();
            while (rs.next()) {
                test = new Test();
                test.setId(rs.getInt(1));
                test.setNums(rs.getInt(2));
                test.setName(rs.getString(3));
            }
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            try {
                if (null != connection) {
                    connection.close();
                }
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        return (T) test;
    }
}

MapperProxy:

public class GPMapperProxy implements InvocationHandler {

    private GPSqlSession sqlSession;

    public GPMapperProxy(GPSqlSession sqlSession) {
        this.sqlSession = sqlSession;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        if (method.getDeclaringClass().getName().equals(GPConfiguration.TestMapperXml.namespace)){
            String sql = GPConfiguration.TestMapperXml.methodSqlMapping.get(method.getName());
            return sqlSession.selectOne(sql,String.valueOf(args[0]));
        }
        return null;
    }
}

我们来测试一下:

  public static void main(String[] args) {
        GPSqlSession gpSqlSession = new GPSqlSession(new GPConfiguration(), new GPSimpleExecutor());
        TestMapper mapper = gpSqlSession.getMapper(TestMapper.class);
        Test test = mapper.selectByPrimaryKey(1);
        System.out.println(test);
    }

输出:
在这里插入图片描述

后记

源码地址:
mybatisV1.0手写版源码地址(Demo在文件夹V1里,sql脚本在resources/sql/下)

你可能感兴趣的:(源码专题)