手寫MyBatis,純手工打造開源框架(第三篇:指揮若定)

說明java

MyBatis版本:3.5.1sql

 

相關歷史文章(閱讀本文以前,您可能須要先看下以前的系列數據庫

Spring Boot MyBatis最全教程:你值得擁有
MyBatis能脫離Spring嗎 一圖縱覽MyBatis的工做原理
從源碼看MyBatis,竟如此簡單 MyBatis的Mapper是什麼`垃圾`  

手寫MyBatis,純手工打造開源框架(第一篇:風雲再起)數組

手寫MyBatis,純手工打造開源框架(第二篇:君臨天下) session

 

前言mybatis

       經過上面咱們已經能夠構建了SqlSessionFactory,接下來的話就是要怎麼獲取一個SqlSession。app

 

1、分析框架

       對於SqlSession的構建的話,須要有一個屬性Configuration,這個屬性在上面的SqlSessionFactory已經有了;另外對於SqlSession的真正的Sql執行是交給了Executor,Executor是真正和數據庫進行交互了,因此須要將數據庫配置信息傳給Executor。工具

 

2、編碼測試

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實現。

我就是我,是顏色不同的煙火。
我就是我,是不同凡響的小蘋果。

à悟空學院:http://t.cn/Rg3fKJD

學院中有Spring Boot相關的課程!點擊「閱讀原文」進行查看!

SpringBoot視頻:http://t.cn/R3QepWG

Spring Cloud視頻:http://t.cn/R3QeRZc

SpringBoot Shiro視頻:http://t.cn/R3QDMbh

SpringBoot交流平臺:http://t.cn/R3QDhU0

SpringData和JPA視頻:http://t.cn/R1pSojf

SpringSecurity5.0視頻:http://t.cn/EwlLjHh

Sharding-JDBC分庫分表實戰:http://t.cn/E4lpD6e

相關文章
相關標籤/搜索