手写Mybatis

一 分析mybatis的工作原理:

如上图所示是mybatis的工作原理

1 首先程序加载全局的配置文件,形成配置文件类

2 通过Mapper的接口形成一个mapper的代理

3 通过调用mapper的代理执行对应的方法,此时代理中会发现,method.getdeclareClass并不是一个类,而是一个接口

4 此时通过执行mapperMethod,也就是接口的方法,因为mepperproxy是组合了sqlsession的,当调用mapper接口的方法时,它通过方法的映射,最终还是调用的sqlsession的接口方法。

5 sqlsession本身不带有接口的实现类,所以此时sqlsession类就组合进来Excutor执行器。通过executor来完成实现。

6 excutor执行的时候需要通过原始jdbc对sql 生成不同的statement比如预编译的prepareStatement,这个时候会借助statementHandler来完成构建Statement

7 可以看到执行到达数据库的过程中,还要经过一个parameterHandler,通过这个类来设置参数。

8 最后查询结果包装结果集通过resultSethandler进行结果集处理,并返回.

二 手写mybaties分析

     如上图所示是对编写一个mybatis的具体思想和步奏的分析,首先我们要有一个使用的方式就是编写一个持久层的jar包并且把它集成到系统里面。其次是具体框架的一些实现步奏与实现思路。参考右半部分的代码实现流程。

三  手写Mybatis 

3.1 使用侧

步奏

1.引入自定义的pom.xml依赖

         <dependency>
            <groupId>cn.lalaframework.boot</groupId>
            <artifactId>worn-persist</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>

2.编辑自定义的配置文件 mybatis-config.xml

<?xml version="1.0" encoding="UTF-8" ?>
<configuration>
    <dataSource>
        <property name="driver" value="com.mysql.jdbc.Driver"/>
        <property name="url" value="jdbc:mysql://192.168.189.3:3306/test"/>
        <property name="username" value="root"/>
        <property name="password" value="root"/>
    </dataSource>


    <mappers>
        <mapper resource="mybatis/UserMapper.xml"/>
    </mappers>
</configuration>

  UserMapper.xml

<?xml version="1.0" encoding="UTF-8" ?>
<mapper namespace="user">

    <select id="selectOne" parameterType="worn.xiao.huolala.persist.User" resultType="worn.xiao.huolala.persist.User">
        select * from user where age=#{age}
    </select>

    <select id="selectList" parameterType="worn.xiao.huolala.persist.User" resultType="worn.xiao.huolala.persist.User">
        select * from user where age=#{age}
    </select>

</mapper>

3.编写掉用代码

public class PersistTest {
    public static void main(String[] args) throws IOException, JDOMException {
        String resource = "mybatis/mybatis-config.xml";
        InputStream resourceAsStream = Resources.class.getClassLoader().getResourceAsStream(resource);
        SqlSessionFactory sqlSessionFactory = SqlSessionFactoryBuilder.build(resourceAsStream);
        SqlSession sqlSession = sqlSessionFactory.openSession();
        User userparameter=new User();
        userparameter.setAge(10);
        List<User> user = sqlSession.selectList("user.selectList",userparameter);
        System.out.println(JSONObject.toJSONString(user));
    }
}

4.执行结果

 

3.2 核心代码实现

1.解析xml生成配置类

 public static SqlSessionFactory build(InputStream inputStream) throws IOException, JDOMException {
        XMLConfigBuilder xmlConfigBuilder=new XMLConfigBuilder(inputStream);
        return  new DefaultSqlSessionFactory(xmlConfigBuilder.parse());
 }

 

public class XMLConfigBuilder {
    private InputStream inputStream;

    public XMLConfigBuilder() {

    }

    public XMLConfigBuilder(InputStream inputStream) {
        this.inputStream = inputStream;
    }

    public Configuration parse() throws IOException, JDOMException {
        SAXBuilder builder = new SAXBuilder();
        Document document = builder.build(inputStream, "");
        Element configration = document.getRootElement();
        Configuration configuration = new Configuration();
        configuration.setDataSource(parseDataSource(configration, "dataSource"));
        parseMappedStatementMap(configuration, configration, "mappers");
        return configuration;
    }

    private void parseMappedStatementMap(Configuration configuration, Element configration, String mappers) throws IOException, JDOMException {
        Element child = configration.getChild(mappers);
        List<Element> children = child.getChildren();
        if (children.size() <= 0) {
            return;
        }
        for (int i = 0; i < children.size(); i++) {
            Element element = children.get(i);
            Attribute resource = element.getAttribute("resource");
            parseMapper(configuration, resource.getValue());
        }

    }

    private void parseMapper(Configuration configuration, String value) throws IOException, JDOMException {
        SAXBuilder builder = new SAXBuilder();
        InputStream resourceAsStream = XMLConfigBuilder.class.getClassLoader().getResourceAsStream(value);
        Document document = builder.build(resourceAsStream, "");
        Element configration = document.getRootElement();
        List<Element> children = configration.getChildren();
        Attribute namespace = configration.getAttribute("namespace");
        for (int i = 0; i < children.size(); i++) {
            Element element = children.get(i);
            Attribute id = element.getAttribute("id");
            Attribute parameterType = element.getAttribute("parameterType");
            Attribute resultType = element.getAttribute("resultType");
            String statementId = namespace.getValue().concat(".").concat(id.getValue());
            String name = element.getName();
            String originSql = element.getText();
            SqlSource sqlSource = getSqlSource(configuration, originSql);
            MappedStatement mappedStatement = new MappedStatement
                    .MappedStatementBuidler()
                    .statementId(statementId)
                    .sqlSource(sqlSource)
                    .parameterType(parameterType.getValue())
                    .sqlCommond(SqlCommond.valueOf(name.toUpperCase(Locale.ROOT)))
                    .resultType(resultType.getValue())
                    .build();
            configuration.getMappedStatementMap().put(statementId, mappedStatement);
        }


    }

    private SqlSource getSqlSource(Configuration configuration, String originSql) {
        ParameterMappingTokenHandler handler = new ParameterMappingTokenHandler();
        GenericTokenParser parser = new GenericTokenParser("#{", "}", handler);
        String finalSql = parser.parse(originSql);
        return new StaticSqlSource(configuration, finalSql, handler.getParameterMappings());
    }

    public DataSource parseDataSource(Element configration, String development) {
        Properties properties = new Properties();
        Element elements = configration.getChild(development);
        List<Element> children =elements.getChildren();
        if (children.size() > 0) {
            for (int i = 0; i < children.size(); i++) {
                Element element = children.get(i);
                Attribute name = element.getAttribute("name");
                Attribute value = element.getAttribute("value");
                properties.setProperty(name.getValue(), value.getValue());
            }
        }
        JdbcDataSource jdbcDataSource = new JdbcDataSource();
        jdbcDataSource.setDriver(properties.getProperty("driver"));
        jdbcDataSource.setUrl(properties.getProperty("url"));
        jdbcDataSource.setUsername(properties.getProperty("username"));
        jdbcDataSource.setPassword(properties.getProperty("password"));
        return jdbcDataSource;
    }
}

2.sqlsession执行器

public class DefaultSqlSession implements SqlSession {

    private Configuration configuration;

    private Executor executor;

    public DefaultSqlSession(){

    }

    public DefaultSqlSession(Configuration configuration,Executor executor){
        this.configuration=configuration;
        this.executor=executor;
    }


    @Override
    public <E> E selectOne(String statementId, Object parameterObj) {
        MappedStatement mappedStatement = configuration.getMappedStatementMap().get(statementId);
        return executor.selectOne(statementId,mappedStatement,parameterObj);
    }

    @Override
    public <E> List<E> selectList(String statementId, Object parameterObj) {
        MappedStatement mappedStatement = configuration.getMappedStatementMap().get(statementId);
        return executor.selectList(statementId,mappedStatement,parameterObj);
    }

}

3 executor 执行器

public class SimpleExecutor implements Executor {

    private Configuration configuration;

    public SimpleExecutor(Configuration configuration) {
        this.configuration = configuration;
    }

    @Override
    public <E> E selectOne(String statementId, MappedStatement mappedStatement, Object parameterObj) {
        List<E> selectList = this.selectList(statementId, mappedStatement, parameterObj);
        if (selectList.size() > 1) {
            throw new RuntimeException("selectOne but has more than one");
        }
        if (selectList.size() == 1) {
            return selectList.get(0);
        }
        return null;
    }

    @Override
    public <E> List<E> selectList(String statementId, MappedStatement mappedStatement, Object parameterObj) {
        try {
            Connection connection = configuration.getDataSource().getConnection();
            SqlSource sqlSource = mappedStatement.getSqlSource();
            BoundSql boundSql = sqlSource.getBoundSql(parameterObj);
            ParameterHandler parameterHandler = configuration.newParameterHandler(mappedStatement, parameterObj, boundSql);
            ResultSetHandler resultHandler = configuration.newResultHandler(mappedStatement);
            StatementHandler statementHandler = configuration.newStatementHandler(this,
                    mappedStatement, parameterObj, resultHandler, boundSql, parameterHandler);
            Statement statement = statementHandler.prepare(connection, 1000);
            statementHandler.parameterize(statement);
            return statementHandler.<E>query(statement, resultHandler);
        } catch (Exception exception) {
            throw new RuntimeException(exception);
        }
    }
}

4 statementhandler 查库

package cn.lalaframework.boot.handler;

import cn.lalaframework.boot.config.MappedStatement;
import cn.lalaframework.boot.executor.Executor;
import cn.lalaframework.boot.sql.BoundSql;


import java.sql.*;
import java.util.List;

public class PreparedStatementHandler implements StatementHandler {

    private Executor executor;

    private MappedStatement mappedStatement;

    private Object parameter;

    private ResultSetHandler resultHandler;

    private BoundSql boundSql;

    private ParameterHandler parameterHandler;


    public PreparedStatementHandler() {

    }

    public PreparedStatementHandler(Executor executor,
                                    MappedStatement mappedStatement,
                                    Object parameter,
                                    ResultSetHandler resultHandler,
                                    BoundSql boundSql,
                                    ParameterHandler parameterHandler) {
        this.executor = executor;
        this.mappedStatement = mappedStatement;
        this.parameter = parameter;
        this.resultHandler = resultHandler;
        this.boundSql = boundSql;
        this.parameterHandler = parameterHandler;
    }

    @Override
    public Statement prepare(Connection connection, Integer transactionTimeout) throws SQLException {
        PreparedStatement preparedStatement = connection.prepareStatement(boundSql.getSql());
        return preparedStatement;
    }

    @Override
    public void parameterize(Statement statement) {
        parameterHandler.setParameters((PreparedStatement) statement);
    }

    @Override
    public int update(Statement statement) throws SQLException {
        PreparedStatement preparedStatement = (PreparedStatement) statement;
        return preparedStatement.executeUpdate();
    }

    @Override
    public <E> List<E> query(Statement statement, ResultSetHandler resultHandler) {
        try {
            PreparedStatement preparedStatement = (PreparedStatement) statement;
            ResultSet resultSet = preparedStatement.executeQuery();
            return resultHandler.<E> handleResult(resultSet);
        } catch (Exception exception) {
            throw new RuntimeException(exception);
        }
    }

    @Override
    public BoundSql getBoundSql() {
        return boundSql;
    }

    @Override
    public ParameterHandler getParameterHandler() {
        return parameterHandler;
    }
}

5 结果集处理 ResultSetWapper

public class ResultSetWapper {
    private ResultSet resultSet;

    private MappedStatement mappedStatement;

    public ResultSetWapper() {

    }

    public ResultSetWapper(ResultSet resultSet, MappedStatement mappedStatement) {
        this.resultSet = resultSet;
        this.mappedStatement = mappedStatement;
    }

    public List<Object> getResult() {
        // 1 获取数据库中的结果集
        // 2 从mappedStatement 获取到结果集的映射
        // 3 封装并返回结果集
        List<Object> resutl = new ArrayList<>();
        try {
            while (resultSet.next()) {
                String resultType = mappedStatement.getResultType();
                Class<?> obj = Class.forName(resultType);
                Object newInstance = obj.newInstance();
                ResultSetMetaData metaData = resultSet.getMetaData();
                int columnCount = metaData.getColumnCount();
                for (int i = 0; i < columnCount; i++) {
                    String columnName = metaData.getColumnName(i+1);
                    Object val = resultSet.getObject(columnName);
                    Field field = obj.getDeclaredField(columnName);
                    field.setAccessible(true);
                    field.set(newInstance, val);
                }
                resutl.add(newInstance);
            }
        } catch (Exception exception) {
            throw new RuntimeException(exception);
        }
        return resutl;
    }
}

以上就是自定义编写一个mybatis的具体步骤。

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值