自定义MyBatis是为了深入了解MyBatis的原理

主要的调用是这样的:

//1.读取配置文件
InputStream in = Resources.getResourceAsStream("SqlMapConfig.xml");
//2.创建SqlSessionFactory工厂
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
SqlSessionFactory factory = builder.build(in);
//3.使用工厂生产SqlSession对象
SqlSession session = factory.openSession();
//4.使用SQLSession创建Dao接口的代理对象
UserDao userDao = session.getMapper(UserDao.class);
//5.使用代理对象执行方法
List<User> users = userDao.findAll();
for (User user : users) {System.out.println(user);
}
//6.释放资源
session.close();
in.close();

首先第一步:将配置文件SqlMapConfig.xml转为流文件

<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE configuration><configuration><!--配置环境--><environments default="mysql"><!--配置mysql的环境--><environment id="mysql"><!--配置事务类型--><transactionManager type="JDBC"></transactionManager><!--配置数据源(连接池)--><dataSource type="POOLED"><!--配置连接数据库的基本信息--><property name="driver" value="com.mysql.jdbc.Driver"/><property name="url"value="jdbc:mysql://localhost:3306/mybatis?useUnicode=true&amp;characterEncoding=utf8"/><property name="username" value="root"/><property name="password" value="1234"/></dataSource></environment></environments><!--指定映射配置文件的位置,映射配置文件指的是每个dao独立的配置文件--><!--<mappers><mapper resource="com/jinke/dao/UserDao.xml"/></mappers>--><!--如果是用注解来配置--><mappers><mapper class="com.jinke.dao.UserDao"/></mappers>
</configuration>

import java.io.InputStream;/*使用类加载器读取配置文件的类*/
public class Resources {public static InputStream getResourceAsStream(String filePath) {return Resources.class.getClassLoader().getResourceAsStream(filePath);}
}

第二步:解析配置文件

import com.jinke.mybatis.cfg.Configuration;
import com.jinke.mybatis.sqlsession.defaults.DefaultSqlSessionFactory;
import com.jinke.mybatis.utils.XMLConfigBuilder;import java.io.InputStream;public class SqlSessionFactoryBuilder {public SqlSessionFactory build(InputStream config) {Configuration cfg = XMLConfigBuilder.loadConfiguration(config);return new DefaultSqlSessionFactory(cfg);}
}

主要是通过反射将属性值保存到map中

import com.jinke.mybatis.annotations.Select;
import com.jinke.mybatis.cfg.Configuration;
import com.jinke.mybatis.cfg.Mapper;
import com.jinke.mybatis.io.Resources;
import org.dom4j.Attribute;
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.HashMap;
import java.util.List;
import java.util.Map;public class XMLConfigBuilder {public static Configuration loadConfiguration(InputStream config) {Configuration cfg = new Configuration();try {SAXReader reader = new SAXReader();Document document = reader.read(config);Element root = document.getRootElement();List<Element> propertyElements = root.selectNodes("//property");for (Element propertyElement : propertyElements) {String name = propertyElement.attributeValue("name");if ("driver".equals(name)) {String driver = propertyElement.attributeValue("value");cfg.setDriver(driver);}if ("url".equals(name)) {String url = propertyElement.attributeValue("value");cfg.setUrl(url);}if ("username".equals(name)) {String username = propertyElement.attributeValue("value");cfg.setUsername(username);}if ("password".equals(name)) {String password = propertyElement.attributeValue("value");cfg.setPassword(password);}}List<Element> mapperElements = root.selectNodes("//mappers/mapper");for (Element mapperElement : mapperElements) {Attribute attribute = mapperElement.attribute("resource");if (attribute != null) {System.out.println("使用的是XML");String mapperPath = attribute.getValue();Map<String, Mapper> mappers = loadMapperConfiguration(mapperPath);cfg.setMappers(mappers);} else {System.out.println("使用的是注解");String daoClassPath = mapperElement.attributeValue("class");Map<String, Mapper> mappers = loadMapperAnnotation(daoClassPath);cfg.setMappers(mappers);}}return cfg;} catch (Exception e) {e.printStackTrace();} finally {try {config.close();} catch (IOException e) {e.printStackTrace();}}return cfg;}private static Map<String, Mapper> loadMapperConfiguration(String mapperPath) throws IOException {InputStream in = null;Map<String, Mapper> mappers = new HashMap<String, Mapper>();try {in = Resources.getResourceAsStream(mapperPath);SAXReader reader = new SAXReader();Document document = reader.read(in);Element root = document.getRootElement();String namespace = root.attributeValue("namespace");List<Element> selectElements = root.selectNodes("//select");for (Element selectElement : selectElements) {String id = selectElement.attributeValue("id");String resultType = selectElement.attributeValue("resultType");String queryString = selectElement.getText();String key = namespace + "." + id;Mapper mapper = new Mapper();mapper.setQueryString(queryString);mapper.setResultType(resultType);mappers.put(key, mapper);}return mappers;} catch (Exception e) {e.printStackTrace();}return mappers;}private static Map<String, Mapper> loadMapperAnnotation(String daoClassPath) throws Exception {Map<String, Mapper> mappers = new HashMap<String, Mapper>();Class daoClass = Class.forName(daoClassPath);Method[] methods = daoClass.getMethods();for (Method method : methods) {boolean isAnnotated = method.isAnnotationPresent(Select.class);if (isAnnotated) {Mapper mapper = new Mapper();Select selectAnno = method.getAnnotation(Select.class);String queryString = selectAnno.value();mapper.setQueryString(queryString);Type type = method.getGenericReturnType();if (type instanceof ParameterizedType) {ParameterizedType ptype = (ParameterizedType) type;Type[] types = ptype.getActualTypeArguments();Class domainClass = (Class) types[0];String resultType = domainClass.getName();mapper.setResultType(resultType);}String methodName = method.getName();String className = method.getDeclaringClass().getName();String key = className + "." + methodName;mappers.put(key, mapper);}}return mappers;}
}

第三步:DefaultSqlSessionFactory工厂生产出DefaultSqlSession对象

import com.jinke.mybatis.cfg.Configuration;
import com.jinke.mybatis.sqlsession.SqlSession;
import com.jinke.mybatis.sqlsession.SqlSessionFactory;public class DefaultSqlSessionFactory implements SqlSessionFactory {private Configuration cfg;public DefaultSqlSessionFactory(Configuration cfg) {this.cfg = cfg;}public SqlSession openSession() {return new DefaultSqlSession(cfg);}
}

第四步:DefaultSqlSession执行动态代理

import com.jinke.mybatis.cfg.Configuration;
import com.jinke.mybatis.sqlsession.SqlSession;
import com.jinke.mybatis.sqlsession.proxy.MapperProxy;
import com.jinke.mybatis.utils.DataSourceUtil;import java.lang.reflect.Proxy;
import java.sql.Connection;
import java.sql.SQLException;public class DefaultSqlSession implements SqlSession {private Configuration cfg;private Connection connection;public DefaultSqlSession(Configuration cfg) {this.cfg = cfg;this.connection = DataSourceUtil.getConnection(cfg);}public <T> T getMapper(Class<T> daoInterfaceClass) {return (T) Proxy.newProxyInstance(daoInterfaceClass.getClassLoader(), new Class[]{daoInterfaceClass}, new MapperProxy(cfg.getMappers(), connection));}public void close() {if (connection != null) {try {connection.close();} catch (SQLException e) {e.printStackTrace();}}}
}

执行sql语句

import com.jinke.mybatis.cfg.Mapper;
import com.jinke.mybatis.utils.Executor;import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.sql.Connection;
import java.util.Map;public class MapperProxy implements InvocationHandler {private Map<String, Mapper> mappers;private Connection connection;public MapperProxy(Map<String, Mapper> mappers, Connection connection) {this.mappers = mappers;this.connection = connection;}public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {String methodName = method.getName();String className = method.getDeclaringClass().getName();String key = className + "." + methodName;Mapper mapper = mappers.get(key);if (mapper == null) {throw new IllegalArgumentException("传入的参数有误");}return new Executor().selectList(mapper, connection);}
}

import com.jinke.mybatis.cfg.Mapper;import java.beans.PropertyDescriptor;
import java.lang.reflect.Method;
import java.sql.*;
import java.util.ArrayList;
import java.util.List;public class Executor {public <E> List<E> selectList(Mapper mapper, Connection conn) {PreparedStatement pstm = null;ResultSet rs = null;try {String queryString = mapper.getQueryString();String resultType = mapper.getResultType();Class domainClass = Class.forName(resultType);pstm = conn.prepareStatement(queryString);rs = pstm.executeQuery();List<E> list = new ArrayList<E>();while (rs.next()) {E obj = (E) domainClass.newInstance();ResultSetMetaData rsmd = rs.getMetaData();int columnCount = rsmd.getColumnCount();for (int i = 1; i < columnCount; i++) {String columnName = rsmd.getColumnName(i);Object columnValue = rs.getObject(columnName);PropertyDescriptor pd = new PropertyDescriptor(columnName, domainClass);Method writeMethod = pd.getWriteMethod();writeMethod.invoke(obj, columnValue);}list.add(obj);}return list;} catch (Exception e) {e.printStackTrace();} finally {release(pstm, rs);}return null;}private void release(PreparedStatement pstm, ResultSet rs) {if (rs != null) {try {rs.close();} catch (SQLException e) {e.printStackTrace();}}if (pstm != null) {try {pstm.close();} catch (SQLException e) {e.printStackTrace();}}}
}

最后放一张文件结构图

代码地址 https://github.com/king1039/MyBatis

欢迎关注我的微信公众号:安卓圈

转载于:https://www.cnblogs.com/anni-qianqian/p/11103040.html

自定义MyBatis相关推荐

  1. springboot多数据源动态切换和自定义mybatis分页插件

    1.配置多数据源 增加druid依赖 完整pom文件 数据源配置文件 route.datasource.driver-class-name= com.mysql.jdbc.Driver route.d ...

  2. Java软件开发:自定义MyBatis持久层框架

    自定义MyBatis持久层框架 1 框架概述 1.1 什么是框架 1.2 框架要解决的问题 1.3 软件开发的分层的重要性 2 MyBatis框架 3 JDBC编程 3.1 JDBC程序的回顾 3.2 ...

  3. MyBatis-学习笔记04【04.自定义Mybatis框架基于注解开发】

    Java后端 学习路线 笔记汇总表[黑马程序员] MyBatis-学习笔记01[01.Mybatis课程介绍及环境搭建][day01] MyBatis-学习笔记02[02.Mybatis入门案例] M ...

  4. MyBatis-学习笔记03【03.自定义Mybatis框架】

    Java后端 学习路线 笔记汇总表[黑马程序员] MyBatis-学习笔记01[01.Mybatis课程介绍及环境搭建][day01] MyBatis-学习笔记02[02.Mybatis入门案例] M ...

  5. 基于自定义Mybatis框架实现数据库操作

    一.场景模拟 基于自定义Mybatis框架和已有的Mysql数据库Mybatis,查询所有用户信息. 二.创建工程并引入自定义Mybatis框架的坐标 <?xml version="1 ...

  6. 自定义Mybatis框架

    一.开发环境的准备及统一 1. Jdk环境:JDK 1.8 64bit 2. Maven环境:MAVEN 3.3.9 二.创建Maven工程并引入坐标 <?xml version="1 ...

  7. Mybatis(5)自定义Mybatis分析以及自定义实现

    执行查询所有和创建代理对象的分析 执行查询所有分析,是对selectList()方法的执行,执行步骤如下 提供:连接信息和映射信息 1.读取配置文件,SqlMapConfig.xml->IUse ...

  8. java day53【 Mybatis框架概述 、 Mybatis 框架快速入门、自定义 Mybatis 框架 】

    第1章 框架概述 1.1 什么是框架 1.1.1 什么是框架 框架(Framework)是整个或部分系统的可重用设计,表现为一组抽象构件及构件实例间交互的方法;另一种 定义认为,框架是可被应用开发者定 ...

  9. Springboot 自定义mybatis 拦截器,实现我们要的扩展

    前言 相信大家对拦截器并不陌生,对mybatis也不陌生. 有用过pagehelper的,那么对mybatis拦截器也不陌生了,按照使用的规则触发sql拦截,帮我们自动添加分页参数 . 那么今天,我们 ...

最新文章

  1. POJ 1184 聪明的打字员
  2. C#技术分享【PDF转换成图片——13种方案】
  3. Android 调试工具集合
  4. sql server数据库查询超时报错
  5. 蜡笔小新里的钢达姆机器人怎么画_写字机器人好用吗? 组装就花了5个小时 还要学习软件、录入字体...
  6. 有一句说一千句,是作家....
  7. PowerDesigner物理数据模型
  8. 4 PP配置-组织架构-定义MRP控制者
  9. 【分享】具有“魔性”的通用软件开发框架
  10. JAVA环境变量安装
  11. 模拟人生 4:如何在游戏中生成收藏品
  12. 球面投影全景图快速拼接
  13. 文本框只能输入数字、字母,屏蔽粘贴
  14. java 主机字节序_java字节序、主机字节序和网络字节序扫盲贴
  15. 卓训教育:家长如何管理好孩子的学习?
  16. 主板后置音频接口图解_不用再看说明书 机箱主板接线全攻略
  17. 有一个棋盘,有64个方格,在第一个方格里面放1粒芝麻重量是0.00001kg,第二个里面放2粒,第三个里面放4,第四个8 ,棋盘上放的所有芝麻的重量(后一个是前一个两倍)。循环练习题。
  18. 公众号快速涨粉方法汇总
  19. 笔记本电脑的鼠标触控面板问题
  20. maya腿的蒙皮旋转枢轴_MAYA更改、移动枢轴点

热门文章

  1. 1050 String Subtraction
  2. 在區塊鏈上建立可更新的智慧合約(一)
  3. CS231n官方笔记授权翻译总集篇发布
  4. 大并发服务器架构 大型网站架构演变
  5. 基于Android的ELF PLT/GOT符号重定向过程及ELF Hook实现
  6. spark 写tidb_优秀的数据工程师,怎么用Spark在TiDB上做OLAP分析
  7. 网易内推java 面试_网易内推面试
  8. 怎样才能到国外做博士后
  9. Thinking In Machine Learning
  10. hdu5375(格雷码问题+简单DP)