`

手写MyBatis,纯手工打造开源框架(第三篇:运筹帷幄)

阅读更多

说明

MyBatis版本:3.5.1

 

相关历史文章(阅读本文之前,您可能需要先看下之前的系列

Spring Boot MyBatis最全教程:你值得拥有
MyBatis能脱离Spring吗一图纵览MyBatis的工作原理
从源码看MyBatis,竟如此简单MyBatis的Mapper是什么`垃圾` 

手写MyBatis,纯手工打造开源框架(第一篇:风云再起)

手写MyBatis,纯手工打造开源框架(第二篇:君临天下) 

 

前言

       通过上面我们已经可以构建了SqlSessionFactory,接下来的话就是要怎么获取一个SqlSession。

 

一、分析

       对于SqlSession的构建的话,需要有一个属性Configuration,这个属性在上面的SqlSessionFactory已经有了;另外对于SqlSession的真正的Sql执行是交给了Executor,Executor是真正和数据库进行交互了,所以需要将数据库配置信息传给Executor。

 

二、编码

2.1 Executor

       构造SqlSession需要有Executor,我们先创建一个Executor接口:

package com.kfit.mybatis.session;

import java.util.List;

import com.kfit.mybatis.config.MapperStatement;

public interface Executor {
     <E> List<E> query(MapperStatement ms, Object parameter);
}
 

       我们实现一个最基本的SimpleExecutor:

package com.kfit.mybatis.session.impl;

import java.util.List;

import com.kfit.mybatis.config.JdbcProperties;
import com.kfit.mybatis.config.MapperStatement;
import com.kfit.mybatis.session.Executor;

public class SimpleExecutor implements Executor {
    private JdbcProperties jdbcProperties;

    public SimpleExecutor(JdbcProperties jdbcProperties) {
        this.jdbcProperties = jdbcProperties;
    }

    public <E> List<E> query(MapperStatement ms, Object parameter) {
        //具体的方法待实现

        return null;
    }

}
 

说明:

(1)这里我们实现了最基本的Simple,在MyBatis有3情况需要处理,我们实现最简单的方式。

(2)这里我们接收了jdbcproperties为了之后直接进行数据库的连接操作,在mybatis数据库的连接关闭,提交,回滚是有一个事务类Transaction。

 

2.2 SqlSessionFactory

       在SqlSessionFactory中添加一个获取SqlSession的方法:

public interface SqlSessionFactory {
    public Configuration getConfiguration();
    public SqlSession openSession();
}
 

 

       在DefaultSqlSessionFactory实现openSession()方法:

    public SqlSession openSession() {
        Executor executor = new SimpleExecutor(configuration.getJdbcProperties());
        SqlSession sqlSession = new DefaultSqlSession(configuration, executor);
        return sqlSession;
    }
 

 

2.3 SimpleExecutor数据库操作

       我们这个对数据库操作的核心代码:

 

package com.kfit.mybatis.session.impl;

import java.lang.reflect.Field;
import java.lang.reflect.Type;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

import com.kfit.mybatis.config.JdbcProperties;
import com.kfit.mybatis.config.MapperStatement;
import com.kfit.mybatis.session.Executor;

public class SimpleExecutor implements Executor {
    private JdbcProperties jdbcProperties;

    public SimpleExecutor(JdbcProperties jdbcProperties) {
        this.jdbcProperties = jdbcProperties;
    }

    public <E> List<E> query(MapperStatement ms, Object parameter) {
        List<E> ret = new ArrayList<E>();
        // 具体的方法待实现
        try {
            // 加载驱动
            Class.forName(jdbcProperties.getDriver());
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        Connection connection = null;

        PreparedStatement preparedStatement = null;
        ResultSet resultSet = null;
        try {
            // 获取连接
            connection = DriverManager.getConnection(jdbcProperties.getUrl(), jdbcProperties.getUsername(),
                    jdbcProperties.getPassword());
            // 预编译sql语句
            preparedStatement = connection.prepareStatement(ms.getSql());
            // 处理sql语句中的占位符
            parameterize(preparedStatement, parameter);
            // 执行sql语句
            resultSet = preparedStatement.executeQuery();
            // 处理结果
            handlerResultSet(resultSet, ret, ms.getResultType());
        } catch (SQLException e) {
            e.printStackTrace();
        }

        return ret;
    }

    private void parameterize(PreparedStatement preparedStatement, Object parameter) throws SQLException {
        if (parameter instanceof String) {
            preparedStatement.setString(1, (String) parameter);
        } else if (parameter instanceof Long) {
            preparedStatement.setLong(1, (Long) parameter);
        } else if (parameter instanceof Integer) {
            preparedStatement.setInt(1, (Integer) parameter);
        }
    }

    private <E> void handlerResultSet(ResultSet resultSet, List<E> ret, String className) {
        Class<E> clazz = null;
        try {
            clazz = (Class<E>) Class.forName(className);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        try {
            while (resultSet.next()) {
                // 通过反射实例化对象
                Object entity = clazz.newInstance();
                // 使用反射工具将resultSet中的数据填充到entity中
                // id,name,sex,age
                // 获取实体类的所有属性,返回Field数组
                Field[] fields = clazz.getDeclaredFields();
                for (Field field : fields) {
                    field.setAccessible(true);
                    String fname = field.getName();
                    Type type = field.getGenericType();
                    if (type.toString().equals("class java.lang.String")) {
                        String column = resultSet.getString(fname);
                        field.set(entity, column);
                    }else if (type.toString().equals("long")) {
                        Long column = resultSet.getLong(fname);
                        field.set(entity, column);
                    }
                }
                ret.add((E) entity);
            }
        } catch (SQLException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
    }

}
 

说明:

(1)在MyBatis中这个代码是分好几个类进行处理的,这里为了讲解方便,统一放在一个类中。

(2)数据库的连接操作:这里使用jdbc连接数据库获取到connection进行操作。

(3)使用泛型处理返回的结果(handlerResultSet)。

 

2.4 SqlSession的方法

       到这里,我们就可以编写SqlSession的方法了,这里定义两个方法SelectOne和SelectList();

 

public interface SqlSession {
     <T> T selectOne(String statement, Object parameter);
     <E> List<E> selectList(String statement);
<E> List<E> selectList(String statement, Object parameter);
}
 

       对应的DefaultSqlSession:

 

package com.kfit.mybatis.session.impl;


import java.util.List;

import com.kfit.mybatis.config.Configuration;
import com.kfit.mybatis.session.Executor;
import com.kfit.mybatis.session.SqlSession;

public class DefaultSqlSession implements SqlSession {
    private Configuration configuration;
    private Executor executor;
    public DefaultSqlSession(Configuration configuration,Executor executor) {
        this.configuration= configuration;
        this.executor = executor;
    }


    public <E> List<E> selectList(String statement) {
        return executor.query(configuration.getMapperStatement(statement),null);
    }

public <E> List<E> selectList(String statement,Object parameter) {
        return executor.query(configuration.getMapperStatement(statement), parameter);
    }


    public <T> T selectOne(String statement,Object parameter) {
        List<T> list = executor.query(configuration.getMapperStatement(statement),parameter);
        if(list.size()>0) {
            return list.get(0);
        }
        return null;
    }
}

 

 

说明:DefaultSqlSession的具体处理交给了Executor,所以这里的具体的实现就比较简单了。

2.5 测试下

       在main方法来进行测试一下吧:

 

 
   public static void main(String[] args) {
        String resource = "mybatis-config.xml";
        InputStream inputStream = App.class.getClassLoader().getResourceAsStream(resource);
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        System.out.println(sqlSessionFactory);
        System.out.println(sqlSessionFactory.getConfiguration().getJdbcProperties().getUrl());

        SqlSession sqlSession = sqlSessionFactory.openSession();


        Demo demo = null;
        List<Demo> demos = null;

        //使用sqlSession直接查询
        demo = sqlSession.selectOne("com.kfit.mybatis.demo.mapper.DemoMapper.getById",1L);
        System.out.println(demo);
        demos = sqlSession.selectList("com.kfit.mybatis.demo.mapper.DemoMapper.getAll");
        System.out.println(demos);

    }
 

       这个方法和之前写mybatis的使用方式上是一模一样的,运行看下效果吧:

Demo[id=1, name=张三1]

[Demo [id=1, name=张三1], Demo [id=9, name=张三], Demo [id=10, name=张三], Demo [id=11, name=张三], Demo [id=12, name=张三], Demo [id=13, name=张三]]

 

 

       看到如此帅气的结果,这是爽歪歪,厉害了我的哥。本篇就先介绍到这里,下一篇我们将会介绍无敌的Mapper实现。

我就是我,是颜色不一样的烟火。
我就是我,是与众不同的小苹果。

à悟空学院:https://t.cn/Rg3fKJD

学院中有Spring Boot相关的课程!点击「阅读原文」进行查看!

SpringBoot视频:http://t.cn/A6ZagYTi

Spring Cloud视频:http://t.cn/A6ZagxSR

SpringBoot Shiro视频:http://t.cn/A6Zag7IV

SpringBoot交流平台:https://t.cn/R3QDhU0

SpringData和JPA视频:http://t.cn/A6Zad1OH

SpringSecurity5.0视频:http://t.cn/A6ZadMBe

Sharding-JDBC分库分表实战http://t.cn/A6ZarrqS

分布式事务解决方案「手写代码」:http://t.cn/A6ZaBnIr

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics