手写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實現。
我就是我,是顏色不一樣的煙火。我就是我,是與眾不同的小蘋果。
à悟空學院: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
posted on 2019-08-20 11:13?悟纖 閱讀(...) 評論(...) 編輯 收藏轉載于:https://www.cnblogs.com/springboot-wuqian/p/11381814.html
總結
以上是生活随笔為你收集整理的手写MyBatis,纯手工打造开源框架(第三篇:运筹帷幄)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: E0864vector不是模板
- 下一篇: STM32嵌入式开发常用词汇词组及缩写汇