目录

一.mybatis极简示例

  1.1 创建mybatis配置文件

  1.2 创建数据库表

  1.3 创建javabean

  1.4 创建mapper映射文件

  1.5 运行测试

二.mybatis的几大“组件”

  2.1 SqlSessionFactoryBuilder

  2.2 SqlSessionFactory

  2.3 SqlSession

  2.4 Executor

  2.5 StatementHandler

  2.6 ParameterHandler

  2.7 ResultSetHandler

  2.8 TypeHandler

三.总结

  写这篇博客,是因为一个面试题“能介绍一下MyBatis执行sql的整个流程吗?”

  之前也看过一下博客,知道大概的流程,无非就是:启动->解析配置文件->创建executor->绑定参数->执行sql->结果集映射,因为没有看过源码,听别人解释,自己心里还是有点虚的,毕竟也不知道别人讲的是否正确,使用MyBatis也快一年了,所以写这篇博客总结一下。

  原文地址:https://www.cnblogs.com/-beyond/p/13232624.html

一.mybatis极简示例

1.1 创建mybatis配置文件

  文件名随意,这里命名为为mybatis-config.xml,内容如下:

  1. <?xml version="1.0" encoding="UTF-8" ?>
  2. <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
  3. "http://mybatis.org/dtd/mybatis-3-config.dtd">
  4.  
  5. <configuration>
  6. <environments default="development">
  7. <environment id="development">
  8. <transactionManager type="JDBC"/>
  9. <dataSource type="POOLED">
  10. <property name="driver" value="com.mysql.jdbc.Driver"/>
  11. <property name="url" value="jdbc:mysql://localhost:3306/test"/>
  12. <property name="username" value="root"/>
  13. <property name="password" value="123456"/>
  14. </dataSource>
  15. </environment>
  16. </environments>
  17. <mappers>
  18. <mapper resource="cn/ganlixin/mappers/UserMapper.xml"/>
  19. </mappers>
  20. </configuration>

1.2 创建数据表

  在test数据库中创建user表:

  1. create table user (
  2. id int not null primary key auto_increment,
  3. name char(20) not null,
  4. age int default 0,
  5. addr char(20) default ''
  6. ) engine=innodb default charset=utf8mb4;
  7.  
  8. insert into user value (1, 'aaa', 18, '北京');

  

1.3 创建javabean

  创建User类,包含4个字段:

  1. package cn.ganlixin.model;
  2.  
  3. public class User {
  4. private Integer id;
  5. private String name;
  6. private Integer age;
  7. private String addr;
  8.  
  9. // 省略getter、setter、toString
  10. }

  

1.4 创建mapper文件

  创建UserMapper.xml文件:

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
  3. "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
  4.  
  5. <mapper namespace="cn.ganlixin.mappers.UserMapper">
  6. <select id="selectUserById" parameterType="int" resultType="cn.ganlixin.model.User">
  7. select * from user where id=#{id}
  8. </select>
  9.  
  10. <delete id="deleteUserById" parameterType="int">
  11. delete from user where id=#{id}
  12. </delete>
  13. </mapper>

  

1.5 运行测试

  1. public class TestMyBatis {
  2. public static void main(String[] args) throws IOException {
  3. String config = "resources/mybatis-config.xml";
  4. InputStream resourceAsStream = Resources.getResourceAsStream(config);
  5. SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
  6. SqlSession sqlSession = sqlSessionFactory.openSession();
  7.  
  8. User user = (User) sqlSession.selectOne("cn.ganlixin.mappers.UserMapper.selectUserById", 1);
  9. System.out.println(user); // User{id=1, name='aaa', age=18, addr='北京'}
  10.  
  11. // 下面的delete不会生效,因为mybatis默认没有开启自动提交
  12. int delete = sqlSession.delete("cn.ganlixin.mappers.UserMapper.deleteUserById", 1);
  13. System.out.println(delete); // 1
  14. }
  15. }

  到这里,一个简单的mybatis使用示例就完成了,后面的分析根据上面这个TestMyBatis的执行流程进行分析的

二.mybatis的几大“组件”

  我这里说的“组件”,可以理解为Mybatis执行过程中的很重要的几个模块。

2.1 SqlSessionFactoryBuilder

  从名称长可以看出来使用的建造者设计模式(Builder),用于构建SqlSessionFactory对象

  1.解析mybatis的xml配置文件,然后创建Configuration对象(对应<configuration>标签);

  2.根据创建的Configuration对象,创建SqlSessionFactory(默认使用DefaultSqlSessionFactory);

2.2 SqlSessionFactory

  从名称上可以看出使用的工厂模式(Factory),用于创建并初始化SqlSession对象(数据库会话)

  1.调用openSession方法,创建SqlSession对象,可以将SqlSession理解为数据库连接(会话);

  2.openSession方法有多个重载,可以创建SqlSession关闭自动提交、指定ExecutorType、指定数据库事务隔离级别….

  1. package org.apache.ibatis.session;
  2. import java.sql.Connection;
  3.  
  4. public interface SqlSessionFactory {
  5. /**
  6. * 使用默认配置
  7. * 1.默认不开启自动提交
  8. * 2.执行器Executor默认使用SIMPLE
  9. * 3.使用数据库默认的事务隔离级别
  10. */
  11. SqlSession openSession();
  12.  
  13. /**
  14. * 指定是否开启自动提交
  15. * @param autoCommit 是否开启自动提交
  16. */
  17. SqlSession openSession(boolean autoCommit);
  18.  
  19. /**
  20. * 根据已有的数据库连接创建会话(事务)
  21. * @param connection 数据库连接
  22. */
  23. SqlSession openSession(Connection connection);
  24.  
  25. /**
  26. * 创建连接时,指定数据库事务隔离级别
  27. * @param level 事务隔离界别
  28. */
  29. SqlSession openSession(TransactionIsolationLevel level);
  30.  
  31. /**
  32. * 创建连接时,指定执行器类型
  33. * @param execType 执行器
  34. */
  35. SqlSession openSession(ExecutorType execType);
  36.  
  37. SqlSession openSession(ExecutorType execType, boolean autoCommit);
  38. SqlSession openSession(ExecutorType execType, TransactionIsolationLevel level);
  39. SqlSession openSession(ExecutorType execType, Connection connection);
  40.  
  41. /**
  42. * 获取Configuration对象,也就是解析xml配置文件中的<configuration>标签后的数据
  43. */
  44. Configuration getConfiguration();
  45. }

  

2.3 SqlSession

  如果了解web开发,就应该知道cookie和session吧,SqlSession的session和web开发中的session概念类似。

  session,译为“会话、会议”,数据的有效时间范围是在会话期间(会议期间),会话(会议)结束后,数据就清除了。

  也可以将SqlSession理解为一个数据库连接。

  SqlSession是一个接口,定义了很多操作数据库的方法声明:

  1. public interface SqlSession extends Closeable {
  2. /* 获取数据库连接 */
  3. Connection getConnection();
  4.  
  5. /* 数据库的增删改查 */
  6. <T> T selectOne(String statement);
  7. <E> List<E> selectList(String statement);
  8. int update(String statement, Object parameter);
  9. int delete(String statement, Object parameter);
  10.  
  11. /* 事务回滚与提交 */
  12. void rollback();
  13. void commit();
  14.  
  15. /* 清除一级缓存 */
  16. void clearCache();
  17.  
  18. // 此处省略了很多方法
  19. }

  SqlSession只是定义了执行sql的一些方法,而具体的实现由子类来完成,比如SqlSession有一个接口实现类DefaultSqlSession。

  MyBatis中通过Executor来执行sql的,在创建SqlSession的时候(openSession),同时会创建一个Executor对象,如下:

  1. @Override
  2. public SqlSession openSession() {
  3. return openSessionFromDataSource(configuration.getDefaultExecutorType(), null, false);
  4. }
  5.  
  6. private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {
  7. Transaction tx = null;
  8. try {
  9. final Environment environment = configuration.getEnvironment();
  10. final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);
  11. tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);
  12.  
  13. // 利用传入的参数,创建executor对象
  14. final Executor executor = configuration.newExecutor(tx, execType);
  15. return new DefaultSqlSession(configuration, executor, autoCommit);
  16. } catch (Exception e) {
  17. closeTransaction(tx); // may have fetched a connection so lets call close()
  18. throw ExceptionFactory.wrapException("Error opening session. Cause: " + e, e);
  19. } finally {
  20. ErrorContext.instance().reset();
  21. }
  22. }

2.4 Executor

  Executor(人称“执行器”)是一个接口,定义了对JDBC的封装;

  MyBatis中提供了多种执行器,如下:

  

  上面的图中,虽然列出了5个Executor(BaseExecutor是抽象类),其实Executor只有三种:

  1. public enum ExecutorType {
  2. SIMPLE, // 简单
  3. REUSE, // 复用
  4. BATCH; // 批量
  5. }

  CacheExecutor其实是一个Executor代理类,包含一个delegate,需要创建时手动传入(要入simple、reuse、batch三者之一);

  ClosedExecutor,所有接口都会抛出异常,表示一个已经关闭的Executor;

  创建SqlSession时,默认使用的是SimpleExecutor;

  下面是创建Executor的代码:org.apache.ibatis.session.Configuration#newExecutor()

  

  上面说了,Executor是对JDBC的封装。当我们使用JDBC来执行sql时,一般会先预处理sql,也就是conn.prepareStatement(sql),获取返回的PreparedStatement对象(实现了Statement接口),再调用statement的executeXxx()来执行sql。

  也就是说,Executor在执行sql的时候也是需要创建Statement对象的,下面以SimpleExecutor为例:

  

2.5 StatementHandler

  在JDBC中,是调用Statement.executeXxx()来执行sql;

  在MyBatis,也是调用Statement.executeXxx()来执行sql,此时就不得不提StatementHandler,可以将其理解为一个工人,他的工作包括

  1.对sql进行预处理;

  2.调用statement.executeXxx()执行sql;

  3.将数据库返回的结果集进行对象转换(ORM);

  1. public interface StatementHandler {
  2. /**
  3. * 获取预处理对象
  4. */
  5. Statement prepare(Connection connection, Integer transactionTimeout) throws SQLException;
  6.  
  7. /**
  8. * 进行预处理
  9. */
  10. void parameterize(Statement statement) throws SQLException;
  11.  
  12. /**
  13. * 批量sql(内部调用statement.addBatch)
  14. */
  15. void batch(Statement statement) throws SQLException;
  16.  
  17. /**
  18. * 执行更新操作
  19. * @return 修改的记录数
  20. */
  21. int update(Statement statement) throws SQLException;
  22.  
  23. /**
  24. * 执行查询操作
  25. * @param statement sql生成的statement
  26. * @param resultHandler 结果集的处理逻辑
  27. * @return 查询结果
  28. */
  29. <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException;
  30.  
  31. <E> Cursor<E> queryCursor(Statement statement) throws SQLException;
  32. BoundSql getBoundSql();
  33. ParameterHandler getParameterHandler();
  34. }

  StatementHandler的相关子类如下图所示:

  

  以BaseStatementHandler为例:

  

2.6 ParameterHandler

  ParameterHandler的功能就是sql预处理后,进行设置参数:

  1. public interface ParameterHandler {
  2.  
  3. Object getParameterObject();
  4.  
  5. void setParameters(PreparedStatement ps) throws SQLException;
  6. }

  ParamterHandler有一个DefaultParameterHandler,下面是其重写setParameters的代码:

  

2.7 ResultSetHandler

  当执行statement.execute()后,就可以通过statement.getResultSet()来获取结果集,获取到结果集之后,MyBatis会使用ResultSetHandler来将结果集的数据转换为Java对象(ORM映射)。

  1. public interface ResultSetHandler {
  2. /**
  3. * 从statement中获取结果集,并将结果集的数据库属性字段映射到Java对象属性
  4. * @param stmt 已经execute的statement,调用state.getResultSet()获取结果集
  5. * @return 转换后的数据
  6. */
  7. <E> List<E> handleResultSets(Statement stmt) throws SQLException;
  8.  
  9. <E> Cursor<E> handleCursorResultSets(Statement stmt) throws SQLException;
  10. void handleOutputParameters(CallableStatement cs) throws SQLException;
  11. }

  ResultSetHandler有一个实现类,DefaultResultHandler,其重写handlerResultSets方法,如下:

  

2.8 TypeHandler

  TypeHandler主要用在两个地方:

  1.参数绑定,发生在ParameterHandler.setParamenters()中。

  MyBatis中,可以使用<resultMap>来定义结果的映射关系,包括每一个字段的类型,比如下面这样:

  1. <resultMap id="baseMap" type="cn.ganlixin.model.User">
  2. <id column="uid" property="id" jdbcType="INTEGER" />
  3. <result column="uname" property="name" jdbcType="VARCHAR" />
  4. </resultMap>

  TypeHandler,可以对某个字段按照xml中配置的类型进行设置值,比如设置sql的uid参数时,类型为INTEGER(jdbcType)。

  2.获取结果集中的字段值,发生在ResultSetHandler处理结果集的过程中。

  TypeHandler的定义如下:

  1. public interface TypeHandler<T> {
  2.  
  3. /**
  4. * 设置预处理参数
  5. *
  6. * @param ps 预处理statement
  7. * @param i 参数位置
  8. * @param parameter 参数值
  9. * @param jdbcType 参数的jdbc类型
  10. */
  11. void setParameter(PreparedStatement ps, int i, T parameter, JdbcType jdbcType) throws SQLException;
  12.  
  13. /**
  14. * 获取一条结果集的某个字段值
  15. *
  16. * @param rs 一条结果集
  17. * @param columnName 列名(字段名称)
  18. * @return 字段值
  19. */
  20. T getResult(ResultSet rs, String columnName) throws SQLException;
  21.  
  22. /**
  23. * 获取一条结果集的某个字段值(按照字段的顺序获取)
  24. *
  25. * @param rs 一条结果集
  26. * @param columnIndex 字段列的顺序
  27. * @return 字段值
  28. */
  29. T getResult(ResultSet rs, int columnIndex) throws SQLException;
  30.  
  31. T getResult(CallableStatement cs, int columnIndex) throws SQLException;
  32. }

  

三.总结

  对于上面的一些组件进行介绍后,这里将其串联起来,那么就能知道mybatis执行sql的具体流程了,于是我花了下面这个流程:

  

  原文地址:https://www.cnblogs.com/-beyond/p/13232624.html

  

MyBatis执行流程的各阶段介绍的更多相关文章

  1. Mybatis执行流程浅析(附深度文章推荐&面试题集锦)

    首先推荐一个简单的Mybatis原理视频教程,可以作为入门教程进行学习:点我 (该教程讲解的是如何手写简易版Mybatis) 执行流程的理解 理解Mybatis的简单流程后自己手写一个,可以解决百分之 ...

  2. mybatis 执行流程以及初用错误总结

    mappper 配置文件  头文件: 1.   <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" &q ...

  3. Mybatis执行流程学习之手写mybatis雏形

    Mybatis是目前开发中最常用的一款基于ORM思想的半自动持久层框架,平时我们都仅仅停留在使用阶段,对mybatis是怎样运行的并不清楚,今天抽空找到一些资料自学了一波,自己写了一个mybatis的 ...

  4. mybatis执行流程

    mybatis 简介 开源的持久层框架:代码简洁,写sql,性能还可以.容易掌握 执行图 文字说明 先创建核心配置文件(sqlMapConfig.xml) 再创建映射文件(可以有多个 ~ 通常有多少张 ...

  5. 生命周期和作用域 & mybatis执行流程

    流程 sqlSessionFactory 实例化后  --> transactional事务管理-->创建executor执行器-->创建SqlSession-->实现增删改查 ...

  6. Mybatis执行流程浅析

    从三个主要的对象SqlSessionFactoryBuilder->SqlSessionFactory->SqlSession说起 inputStream = Resources.getR ...

  7. Mybatis 系列10-结合源码解析mybatis 的执行流程

    [Mybatis 系列10-结合源码解析mybatis 执行流程] [Mybatis 系列9-强大的动态sql 语句] [Mybatis 系列8-结合源码解析select.resultMap的用法] ...

  8. Mybatis功能架构及执行流程

    原文地址:http://blog.51cto.com/12222886/2052647 一.功能架构设计 功能架构讲解: 我们把Mybatis的功能架构分为三层: (1) API接口层:提供给外部使用 ...

  9. mybatis执行过程及经典面试题

    Mybatis执行流程 mybatis中xml解析是通过SqlSessionFactoryBuilder.build()方法. 初始化mybatis(解析xml文件构建成Configuration对象 ...

随机推荐

  1. JQuery实现对html结点的操作(创建,添加,删除)

    效果图: <!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <ti ...

  2. 第七届蓝桥杯JavaA组省赛真题

    解题代码部分来自网友,如果有不对的地方,欢迎各位大佬评论 题目1.煤球数量 煤球数目 有一堆煤球,堆成三角棱锥形.具体: 第一层放1个, 第二层3个(排列成三角形), 第三层6个(排列成三角形), 第 ...

  3. java实现生日相同概率

    假设所有年份都只有365天,求n个人中,出现生日相同的概率. 输入n 输出相同的概率(保留3位有效数字即可) import java.util.*; public class X { // n个人出现 ...

  4. docker-compose mysql和node连接认证mongo问题

    前言 最近,想部署一个自己的项目,鉴于自己的服务器是VPS(虚拟主机),配置也不够,就想到了用 docker 直接部署好了,这样既方便部署也方便不用的时候卸载或更新 然后本地搭建了环境,踩了一些坑,在 ...

  5. (九)不安全的HTTP方法

    01 漏洞描述 <HTTP | HTTP报文>中介绍了HTTP的请求方法.在这些方法中,HTTP定义了一组被称为安全方法的方法:GET.HEAD.OPTIONS.TRACE,这些方法不会产 ...

  6. CMAKE工具学习

    最近在学习各大物联网平台的SDK包,发现其工程都使用了一种叫cmake的工具在管理代码.于是花了一天时间简单学习了解了cmake工具,其目的是让自己能读懂使用该工具管理的代码,并能简单使用该工具管理我 ...

  7. 第一章04-Activity中常用的标志位

    Activity的LaunchMode Android中提供了四中Activity的启动模式 1. standard 2. singleTop 3. singleTask 4. signleInsta ...

  8. jQuery实现打飞机游戏

    玩法介绍:不同样式的飞机出来其它飞机会暂停飞行且处于无敌状态,子弹对它无效,你操纵的飞机不能碰到任何飞机,发出的子弹可以攻击正在飞行的飞机,每击落一架飞机会记录分数,你操纵的飞机碰到其它飞机即为游戏结 ...

  9. <WP8开发学习笔记>ApplicationBar(任务栏)的切换以及“黑条问题”

    ApplicationBar(以下简称AppBar)是WP应用相当常见的控件,也很方便.常见的做法是pivot或者panorama的页面切换的时候,AppBar跟随切换对应的按钮或者不显示按钮,如下图 ...

  10. Charles抓包1-Charles安装汉化(附正版注册码)

    目录 1.下载&&安装 2.汉化 1.下载&&安装 charles官网 charles下载 下载后直接安装即可. 2.汉化 下载提供的汉化包charles.jar(加群 ...