从 [MyBatis 原码解析(version:3.2.7)] 中,我们得知,MyBatis去执行SQL都是通过 DefaultSqlSession 中的工具方法去执行的。

那么问题来了,MyBatis 是怎么构造 DefaultSqlSession 的?

通过查看源码,得知 MyBatis 是通过 DefaultSqlSessionFactory 来构造 DefaultSqlSession 的。

DefaultSqlSessionFactory#openSessionFromDataSource(ExecutorType, TransactionIsolationLevel, boolean)

/**
* @param ExecutorType 执行器的类型。MyBatis中提供了三种执行器:SIMPLE, REUSE, BATCH。默认的是 SIMPLE
* @param TransactionIsolationLevel 事务隔离级别
* @param autoCommit 是否自动提交事务
*/
private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {
Transaction tx = null;
try {
final Environment environment = configuration.getEnvironment();
final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment); // 通过 Environment 获取事务工厂 TransactionFactory。没有指定Environment,则使用 ManagedTransactionFactory
tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit); // 从 TransactionFactory 中获取一个 Transaction
final Executor executor = configuration.newExecutor(tx, execType); // 从 Configuration 中获取一个新的 Executor。(Configuration 对应的是 mybatis-config.xml 中的配置)
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();
}
}

重点看一下 Configuration#newExecutor(Transaction transaction, ExecutorType executorType)

public Executor newExecutor(Transaction transaction, ExecutorType executorType) {
executorType = executorType == null ? defaultExecutorType : executorType;
executorType = executorType == null ? ExecutorType.SIMPLE : executorType; // 默认使用 SimpleExecutor
Executor executor;
if (ExecutorType.BATCH == executorType) {
executor = new BatchExecutor(this, transaction); // 使用 BatchExecutor
} else if (ExecutorType.REUSE == executorType) {
executor = new ReuseExecutor(this, transaction); // 使用 ReuseExecutor
} else {
executor = new SimpleExecutor(this, transaction); // 默认使用 SimpleExecutor
}
if (cacheEnabled) {
executor = new CachingExecutor(executor); // 使用 CachingExecutor
}
executor = (Executor) interceptorChain.pluginAll(executor); // 执行所有的MyBatis拦截器,并返回 Executor
return executor;
}

至此,我们找到了MyBatis的一个扩展点——拦截器interceptor。

MyBatis Inteceptor是使用JDK的动态代理来实现的,所以它只能对接口进行拦截。

里面两个很重要的注解是:@Intercepts、@Signature
@Intercepts : 标记要拦截的方法签名
@Signature : 方法签名,唯一的标记一个接口的方法

通过查看源码,我们还可以知道,MyBatis所有的代理拦截都是通过 InterceptorChain.pluginAll(Object target) 来实现的。
至此,我们得到下图:

通过上图可知,Mybatis支持对 Executor 、 StatementHandler 、 ResultSetHandler 和 PameterHandler 进行拦截,也就是说会对这4种对象进行代理。

Executor                : 作用是执行SQL语句(所有的sql),并且对事务、缓存等提供统一接口。(在这一层上做拦截的权限会更大)
StatementHandler : 作用是对 statement 进行预处理,并且提供统一的原子的增、删、改、查接口。(如果要在SQL执行前进行拦截的话,拦截这里就可以了)
ResultSetHandler  : 作用是对返回结果ResultSet进行处理。
PameterHandler    : 作用是对参数进行赋值。

附:

对 TypeHandler 进行扩展:http://mp.weixin.qq.com/s/GLb_-dLVAWYb6-_GWGIF8w
解决问题:
  从SqlServer中取数据,遇到很多列都是Numeric(10,2)类型,指的是字段是数字型,长度为10,小数为两位。Mybatis默认的BigDecimalTypeHandler取到后,都默认变成4位小数,不够的补了0。而上层的要求是,拿到的和数字相关的数据都要2位小数。这时,可以自定义一个 TypeHandler 进行统一处理

TypeHandler 的作用:无论是 MyBatis 在预处理语句(PreparedStatement)中设置一个参数时,还是从结果集中取出一个值时, 都会用类型处理器 TypeHandler 将获取的值以合适的方式转换成 Java 类型。

MyBatis 支持的扩展点(version:3.2.7)的更多相关文章

  1. mybatis支持jdk8等localdate类型

    大家知道,在实体Entity里面,可以使用java.sql.Date.java.sql.Timestamp.java.util.Date来映射到数据库的date.timestamp.datetime等 ...

  2. EntityFramework中支持BulkInsert扩展

    EntityFramework中支持BulkInsert扩展 本文为 Dennis Gao 原创技术文章,发表于博客园博客,未经作者本人允许禁止任何形式的转载. 前言 很显然,你应该不至于使用 Ent ...

  3. yum 安装apache php 使php支持memcached扩展

    在公司上新项目的时候,无论生产环境还是测试环境,都会让运维安装php 环境(lamp/lnmp),并让php支持memcached 的扩展.这里搭建php环境其实主要就是搭建apache 和php.m ...

  4. 【03】Chrome提示印象笔记剪藏插件"已停用不支持的扩展程序"怎么办?

    [03] Chrome提示印象笔记剪藏插件"已停用不支持的扩展程序"怎么办? 刚好也遇上了这个问题,百度了一下,以下是解决方法,亲测可行: 1.首先把需要安装的第三方插件,后缀.c ...

  5. .net core 3.0 Signalr - 04 使用Redis做底板来支持横向扩展

    在实际的系统中,可能需要多台机器部署;然而,Signalr的连接信息是跟站点走的,举个例子 推送系统部署了A.B两个服务器,张三访问A服务器,李四访问B服务器,当张三通过A服务器向李四推送的时候,A服 ...

  6. 使Jackson和Mybatis支持JSR310标准

    1.首先要确保Jackson和Mybatis正确地整合进项目了 2.添加额外的依赖 <dependency> <groupId>org.mybatis</groupId& ...

  7. 记一次 IDEA mybatis.generator 自定义扩展插件

    在使用 idea mybatis.generator 生成的代码,遇到 生成的代码很多重复的地方, 虽然代码是生成的,我们也不应该允许重复的代码出现,因为这些代码后期都要来手动维护. 对于生成时间戳注 ...

  8. springboot + mybatis 支持oracle和mysql切换含源码

    1.springboot 启动类加入bean 如下 // DatabaseIdProvider元素主要是为了支持不同的数据库@Beanpublic DatabaseIdProvider getData ...

  9. 全网唯一开源java开发的支持高扩展,高性能的Mqtt集群broker!

    SMQTT是一款开源的MQTT消息代理Broker, SMQTT基于Netty开发,底层采用Reactor3反应堆模型,支持单机部署,支持容器化部署,具备低延迟,高吞吐量,支持百万TCP连接,同时支持 ...

随机推荐

  1. 连接两个点云中的字段或数据形成新点云以及Opennni Grabber初识

    (1)学习如何连接两个不同点云为一个点云,进行操作前要确保两个数据集中字段的类型相同和维度相等,同时了解如何连接两个不同点云的字段(例如颜色 法线)这种操作的强制约束条件是两个数据集中点的数目必须一样 ...

  2. Ubuntu free以及Linux内存占用大的解释

    -bash-3.00$ free total used free shared buffers cached Mem: 514020 465932 48088 0 15864 348844 -/ bu ...

  3. 关于sentinel LDK加密war包实现应用加密的使用方法

    经过一周多时间的研究,终于对sentinel产品的使用有个基本的掌握.其中走了不少的弯路,特此记录一下,以备后面回顾. 开发前的用料准备: windows 10 x64位, tomcat7 x64bi ...

  4. js之队列01

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...

  5. QTcpSocket使用过程中的一些问题记录

    目前,在将原来C的socket通讯改为使用Qt类库QTcpSocket通讯,在修改过程中遇到不少问题,在此将问题一并记录,以备后面使用. 采用的通讯方式:QTimer定时器.QThread多线程和QT ...

  6. 【6】JVM-内存分配与回收策略

        JAVA技术体系中的自动内存管理实际上就是自动化的解决了给对象分配内存以及回收给对象分配的内存这两个问题.回收部分通过之前的<GC设计思路分析>和<垃圾收集器>这两篇博 ...

  7. android 8 wifi 信号等级

    wifi信号等级 /frameworks/base/wifi/java/android/net/wifi/wifimanager.java calculateSignalLevel为计算信号等级函数, ...

  8. SpringMVC系列(十三)异常处理

    一.简介 • Spring MVC 通过 HandlerExceptionResolver 处理程序的异常,包括 Handler 映射.数据绑定以及目标方法执行时发生的异常.• SpringMVC 提 ...

  9. Bioperl 解析blast的输出结果

    用bioperl 解析blast的默认输出结果, 整理成-m8格式的输出 #!/usr/bin/perl use Bio::SearchIO; my ($blast) = @ARGV; my $sea ...

  10. 8.4 Java 命名规范

    Class: 所有单词的首字母大写, TestJava Method: 第一个单词的首字母小写,之后每个单词的首字母大写, getAddressForMe() Property: 第一个单词的首字母小 ...