MyBatis执行流程的各阶段介绍
目录
1.1 创建mybatis配置文件
1.2 创建数据库表
1.3 创建javabean
1.4 创建mapper映射文件
1.5 运行测试
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,内容如下:
- <?xml version="1.0" encoding="UTF-8" ?>
- <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
- "http://mybatis.org/dtd/mybatis-3-config.dtd">
- <configuration>
- <environments default="development">
- <environment id="development">
- <transactionManager type="JDBC"/>
- <dataSource type="POOLED">
- <property name="driver" value="com.mysql.jdbc.Driver"/>
- <property name="url" value="jdbc:mysql://localhost:3306/test"/>
- <property name="username" value="root"/>
- <property name="password" value="123456"/>
- </dataSource>
- </environment>
- </environments>
- <mappers>
- <mapper resource="cn/ganlixin/mappers/UserMapper.xml"/>
- </mappers>
- </configuration>
1.2 创建数据表
在test数据库中创建user表:
- create table user (
- id int not null primary key auto_increment,
- name char(20) not null,
- age int default 0,
- addr char(20) default ''
- ) engine=innodb default charset=utf8mb4;
- insert into user value (1, 'aaa', 18, '北京');
1.3 创建javabean
创建User类,包含4个字段:
- package cn.ganlixin.model;
- public class User {
- private Integer id;
- private String name;
- private Integer age;
- private String addr;
- // 省略getter、setter、toString
- }
1.4 创建mapper文件
创建UserMapper.xml文件:
- <?xml version="1.0" encoding="UTF-8"?>
- <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
- "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
- <mapper namespace="cn.ganlixin.mappers.UserMapper">
- <select id="selectUserById" parameterType="int" resultType="cn.ganlixin.model.User">
- select * from user where id=#{id}
- </select>
- <delete id="deleteUserById" parameterType="int">
- delete from user where id=#{id}
- </delete>
- </mapper>
1.5 运行测试
- public class TestMyBatis {
- public static void main(String[] args) throws IOException {
- String config = "resources/mybatis-config.xml";
- InputStream resourceAsStream = Resources.getResourceAsStream(config);
- SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
- SqlSession sqlSession = sqlSessionFactory.openSession();
- User user = (User) sqlSession.selectOne("cn.ganlixin.mappers.UserMapper.selectUserById", 1);
- System.out.println(user); // User{id=1, name='aaa', age=18, addr='北京'}
- // 下面的delete不会生效,因为mybatis默认没有开启自动提交
- int delete = sqlSession.delete("cn.ganlixin.mappers.UserMapper.deleteUserById", 1);
- System.out.println(delete); // 1
- }
- }
到这里,一个简单的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、指定数据库事务隔离级别….
- package org.apache.ibatis.session;
- import java.sql.Connection;
- public interface SqlSessionFactory {
- /**
- * 使用默认配置
- * 1.默认不开启自动提交
- * 2.执行器Executor默认使用SIMPLE
- * 3.使用数据库默认的事务隔离级别
- */
- SqlSession openSession();
- /**
- * 指定是否开启自动提交
- * @param autoCommit 是否开启自动提交
- */
- SqlSession openSession(boolean autoCommit);
- /**
- * 根据已有的数据库连接创建会话(事务)
- * @param connection 数据库连接
- */
- SqlSession openSession(Connection connection);
- /**
- * 创建连接时,指定数据库事务隔离级别
- * @param level 事务隔离界别
- */
- SqlSession openSession(TransactionIsolationLevel level);
- /**
- * 创建连接时,指定执行器类型
- * @param execType 执行器
- */
- SqlSession openSession(ExecutorType execType);
- SqlSession openSession(ExecutorType execType, boolean autoCommit);
- SqlSession openSession(ExecutorType execType, TransactionIsolationLevel level);
- SqlSession openSession(ExecutorType execType, Connection connection);
- /**
- * 获取Configuration对象,也就是解析xml配置文件中的<configuration>标签后的数据
- */
- Configuration getConfiguration();
- }
2.3 SqlSession
如果了解web开发,就应该知道cookie和session吧,SqlSession的session和web开发中的session概念类似。
session,译为“会话、会议”,数据的有效时间范围是在会话期间(会议期间),会话(会议)结束后,数据就清除了。
也可以将SqlSession理解为一个数据库连接。
SqlSession是一个接口,定义了很多操作数据库的方法声明:
- public interface SqlSession extends Closeable {
- /* 获取数据库连接 */
- Connection getConnection();
- /* 数据库的增删改查 */
- <T> T selectOne(String statement);
- <E> List<E> selectList(String statement);
- int update(String statement, Object parameter);
- int delete(String statement, Object parameter);
- /* 事务回滚与提交 */
- void rollback();
- void commit();
- /* 清除一级缓存 */
- void clearCache();
- // 此处省略了很多方法
- }
SqlSession只是定义了执行sql的一些方法,而具体的实现由子类来完成,比如SqlSession有一个接口实现类DefaultSqlSession。
MyBatis中通过Executor来执行sql的,在创建SqlSession的时候(openSession),同时会创建一个Executor对象,如下:
- @Override
- public SqlSession openSession() {
- return openSessionFromDataSource(configuration.getDefaultExecutorType(), null, false);
- }
- private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {
- Transaction tx = null;
- try {
- final Environment environment = configuration.getEnvironment();
- final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);
- tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);
- // 利用传入的参数,创建executor对象
- final Executor executor = configuration.newExecutor(tx, execType);
- return new DefaultSqlSession(configuration, executor, autoCommit);
- } catch (Exception e) {
- closeTransaction(tx); // may have fetched a connection so lets call close()
- throw ExceptionFactory.wrapException("Error opening session. Cause: " + e, e);
- } finally {
- ErrorContext.instance().reset();
- }
- }
2.4 Executor
Executor(人称“执行器”)是一个接口,定义了对JDBC的封装;
MyBatis中提供了多种执行器,如下:
上面的图中,虽然列出了5个Executor(BaseExecutor是抽象类),其实Executor只有三种:
- public enum ExecutorType {
- SIMPLE, // 简单
- REUSE, // 复用
- BATCH; // 批量
- }
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);
- public interface StatementHandler {
- /**
- * 获取预处理对象
- */
- Statement prepare(Connection connection, Integer transactionTimeout) throws SQLException;
- /**
- * 进行预处理
- */
- void parameterize(Statement statement) throws SQLException;
- /**
- * 批量sql(内部调用statement.addBatch)
- */
- void batch(Statement statement) throws SQLException;
- /**
- * 执行更新操作
- * @return 修改的记录数
- */
- int update(Statement statement) throws SQLException;
- /**
- * 执行查询操作
- * @param statement sql生成的statement
- * @param resultHandler 结果集的处理逻辑
- * @return 查询结果
- */
- <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException;
- <E> Cursor<E> queryCursor(Statement statement) throws SQLException;
- BoundSql getBoundSql();
- ParameterHandler getParameterHandler();
- }
StatementHandler的相关子类如下图所示:
以BaseStatementHandler为例:
2.6 ParameterHandler
ParameterHandler的功能就是sql预处理后,进行设置参数:
- public interface ParameterHandler {
- Object getParameterObject();
- void setParameters(PreparedStatement ps) throws SQLException;
- }
ParamterHandler有一个DefaultParameterHandler,下面是其重写setParameters的代码:
2.7 ResultSetHandler
当执行statement.execute()后,就可以通过statement.getResultSet()来获取结果集,获取到结果集之后,MyBatis会使用ResultSetHandler来将结果集的数据转换为Java对象(ORM映射)。
- public interface ResultSetHandler {
- /**
- * 从statement中获取结果集,并将结果集的数据库属性字段映射到Java对象属性
- * @param stmt 已经execute的statement,调用state.getResultSet()获取结果集
- * @return 转换后的数据
- */
- <E> List<E> handleResultSets(Statement stmt) throws SQLException;
- <E> Cursor<E> handleCursorResultSets(Statement stmt) throws SQLException;
- void handleOutputParameters(CallableStatement cs) throws SQLException;
- }
ResultSetHandler有一个实现类,DefaultResultHandler,其重写handlerResultSets方法,如下:
2.8 TypeHandler
TypeHandler主要用在两个地方:
1.参数绑定,发生在ParameterHandler.setParamenters()中。
MyBatis中,可以使用<resultMap>来定义结果的映射关系,包括每一个字段的类型,比如下面这样:
- <resultMap id="baseMap" type="cn.ganlixin.model.User">
- <id column="uid" property="id" jdbcType="INTEGER" />
- <result column="uname" property="name" jdbcType="VARCHAR" />
- </resultMap>
TypeHandler,可以对某个字段按照xml中配置的类型进行设置值,比如设置sql的uid参数时,类型为INTEGER(jdbcType)。
2.获取结果集中的字段值,发生在ResultSetHandler处理结果集的过程中。
TypeHandler的定义如下:
- public interface TypeHandler<T> {
- /**
- * 设置预处理参数
- *
- * @param ps 预处理statement
- * @param i 参数位置
- * @param parameter 参数值
- * @param jdbcType 参数的jdbc类型
- */
- void setParameter(PreparedStatement ps, int i, T parameter, JdbcType jdbcType) throws SQLException;
- /**
- * 获取一条结果集的某个字段值
- *
- * @param rs 一条结果集
- * @param columnName 列名(字段名称)
- * @return 字段值
- */
- T getResult(ResultSet rs, String columnName) throws SQLException;
- /**
- * 获取一条结果集的某个字段值(按照字段的顺序获取)
- *
- * @param rs 一条结果集
- * @param columnIndex 字段列的顺序
- * @return 字段值
- */
- T getResult(ResultSet rs, int columnIndex) throws SQLException;
- T getResult(CallableStatement cs, int columnIndex) throws SQLException;
- }
三.总结
对于上面的一些组件进行介绍后,这里将其串联起来,那么就能知道mybatis执行sql的具体流程了,于是我花了下面这个流程:
原文地址:https://www.cnblogs.com/-beyond/p/13232624.html
MyBatis执行流程的各阶段介绍的更多相关文章
- Mybatis执行流程浅析(附深度文章推荐&面试题集锦)
首先推荐一个简单的Mybatis原理视频教程,可以作为入门教程进行学习:点我 (该教程讲解的是如何手写简易版Mybatis) 执行流程的理解 理解Mybatis的简单流程后自己手写一个,可以解决百分之 ...
- mybatis 执行流程以及初用错误总结
mappper 配置文件 头文件: 1. <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" &q ...
- Mybatis执行流程学习之手写mybatis雏形
Mybatis是目前开发中最常用的一款基于ORM思想的半自动持久层框架,平时我们都仅仅停留在使用阶段,对mybatis是怎样运行的并不清楚,今天抽空找到一些资料自学了一波,自己写了一个mybatis的 ...
- mybatis执行流程
mybatis 简介 开源的持久层框架:代码简洁,写sql,性能还可以.容易掌握 执行图 文字说明 先创建核心配置文件(sqlMapConfig.xml) 再创建映射文件(可以有多个 ~ 通常有多少张 ...
- 生命周期和作用域 & mybatis执行流程
流程 sqlSessionFactory 实例化后 --> transactional事务管理-->创建executor执行器-->创建SqlSession-->实现增删改查 ...
- Mybatis执行流程浅析
从三个主要的对象SqlSessionFactoryBuilder->SqlSessionFactory->SqlSession说起 inputStream = Resources.getR ...
- Mybatis 系列10-结合源码解析mybatis 的执行流程
[Mybatis 系列10-结合源码解析mybatis 执行流程] [Mybatis 系列9-强大的动态sql 语句] [Mybatis 系列8-结合源码解析select.resultMap的用法] ...
- Mybatis功能架构及执行流程
原文地址:http://blog.51cto.com/12222886/2052647 一.功能架构设计 功能架构讲解: 我们把Mybatis的功能架构分为三层: (1) API接口层:提供给外部使用 ...
- mybatis执行过程及经典面试题
Mybatis执行流程 mybatis中xml解析是通过SqlSessionFactoryBuilder.build()方法. 初始化mybatis(解析xml文件构建成Configuration对象 ...
随机推荐
- JQuery实现对html结点的操作(创建,添加,删除)
效果图: <!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <ti ...
- 第七届蓝桥杯JavaA组省赛真题
解题代码部分来自网友,如果有不对的地方,欢迎各位大佬评论 题目1.煤球数量 煤球数目 有一堆煤球,堆成三角棱锥形.具体: 第一层放1个, 第二层3个(排列成三角形), 第三层6个(排列成三角形), 第 ...
- java实现生日相同概率
假设所有年份都只有365天,求n个人中,出现生日相同的概率. 输入n 输出相同的概率(保留3位有效数字即可) import java.util.*; public class X { // n个人出现 ...
- docker-compose mysql和node连接认证mongo问题
前言 最近,想部署一个自己的项目,鉴于自己的服务器是VPS(虚拟主机),配置也不够,就想到了用 docker 直接部署好了,这样既方便部署也方便不用的时候卸载或更新 然后本地搭建了环境,踩了一些坑,在 ...
- (九)不安全的HTTP方法
01 漏洞描述 <HTTP | HTTP报文>中介绍了HTTP的请求方法.在这些方法中,HTTP定义了一组被称为安全方法的方法:GET.HEAD.OPTIONS.TRACE,这些方法不会产 ...
- CMAKE工具学习
最近在学习各大物联网平台的SDK包,发现其工程都使用了一种叫cmake的工具在管理代码.于是花了一天时间简单学习了解了cmake工具,其目的是让自己能读懂使用该工具管理的代码,并能简单使用该工具管理我 ...
- 第一章04-Activity中常用的标志位
Activity的LaunchMode Android中提供了四中Activity的启动模式 1. standard 2. singleTop 3. singleTask 4. signleInsta ...
- jQuery实现打飞机游戏
玩法介绍:不同样式的飞机出来其它飞机会暂停飞行且处于无敌状态,子弹对它无效,你操纵的飞机不能碰到任何飞机,发出的子弹可以攻击正在飞行的飞机,每击落一架飞机会记录分数,你操纵的飞机碰到其它飞机即为游戏结 ...
- <WP8开发学习笔记>ApplicationBar(任务栏)的切换以及“黑条问题”
ApplicationBar(以下简称AppBar)是WP应用相当常见的控件,也很方便.常见的做法是pivot或者panorama的页面切换的时候,AppBar跟随切换对应的按钮或者不显示按钮,如下图 ...
- Charles抓包1-Charles安装汉化(附正版注册码)
目录 1.下载&&安装 2.汉化 1.下载&&安装 charles官网 charles下载 下载后直接安装即可. 2.汉化 下载提供的汉化包charles.jar(加群 ...