技术内幕

Mybatis3.4.x技术内幕(二十):PageHelper分页插件源码及原理剖析

做~自己de王妃 提交于 2019-11-28 12:21:00
PageHelper是一款好用的开源免费的Mybatis第三方物理分页插件,其实我并不想加上好用两个字,但是为了表扬插件作者开源免费的崇高精神,我毫不犹豫的加上了好用一词作为赞美。 原本以为分页插件,应该是很简单的,然而PageHelper比我想象的要复杂许多,它做的很强大,也很彻底,强大到使用者可能并不需要这么多功能,彻底到一参可以两用。但是,我认为,作为分页插件,完成物理分页任务是根本,其它的很多智能并不是必要的,保持它够傻够憨,专业术语叫stupid,简单就是美。 我们将简单介绍PageHelper的基本使用和配置参数的含义,重点分析PageHelper作为Mybatis分页插件的实现原理。 1. PageHelper的maven依赖及插件配置 <dependency> <groupId>com.github.pagehelper</groupId> <artifactId>pagehelper</artifactId> <version>4.1.6</version> </dependency> PageHelper除了本身的jar包外,它还依赖了一个叫jsqlparser的jar包,使用时,我们不需要单独指定jsqlparser的maven依赖,maven的间接依赖会帮我们引入。 <!-- com.github.pagehelper为PageHelper类所在包名 -->

Mybatis3.3.x技术内幕(二):动态代理之投鞭断流(自动映射器Mapper的底层实现原理)

天涯浪子 提交于 2019-11-28 10:21:22
一日小区漫步, 我问朋友:Mybatis中声明一个interface接口,没有编写任何实现类,Mybatis就能返回接口实例,并调用接口方法返回数据库数据,你知道为什么不?朋友很是诧异:是啊,我也很纳闷,我们领导告诉我们按照这个模式编写就好了,我同事也感觉很奇怪,虽然我不知道具体是怎么实现的,但我觉得肯定是……(此处略去若干的漫天猜想),但是也不对啊,难道是……(再次略去若干似懂非懂)。 这激发了我写本篇文章的冲动。 动态代理的功能:通过拦截器方法回调,对目标target方法进行增强。 言外之意就是为了增强目标target方法。上面这句话没错,但也不要认为它就是真理,殊不知,动态代理还有 投鞭断流 的霸权,连目标target都不要的科幻模式。 注:本文默认认为,读者对动态代理的原理是理解的,如果不明白target的含义,难以看懂本篇文章,建议先理解动态代理。 1. 自定义JDK动态代理之 投鞭断流 实现自动映射器Mapper 首先定义一个pojo。 public class User { private Integer id; private String name; private int age; public User(Integer id, String name, int age) { this.id = id; this.name = name; this.age =

Mybatis3.3.x技术内幕(八):Mybatis初始化流程(上)

坚强是说给别人听的谎言 提交于 2019-11-27 08:35:02
Mybatis初始化流程,其实就是组装重量级All-In-One对象Configuration的过程,主要分为系统环境参数初始化和Mapper映射初始化,其中Mapper映射初始化尤为重要。 inputStream = Resources.getResourceAsStream("mybatis-config.xml"); sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) { XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties); return new DefaultSqlSessionFactory(parser.parse()); } parser.parse()方法,已经返回了组装完毕的 Configuration对象。 流程进入XMLConfigBuilder.parse()方法。 public Configuration parse() {

Mybatis3.3.x技术内幕(十):Mybatis初始化流程(下)

可紊 提交于 2019-11-27 08:34:36
Mybatis初始化过程中,解析parameterMap、resultMap、"select|insert|update|delete"元素,无疑是重头戏。本节将详细分析解析过程。 元素 parameterMap 将会解析为ParameterMap对象,该对象包含一个List<ParameterMapping>集合,是one-to-many关系。 元素 resultMap将会解析为ResultMap对象,该对象包含一个List<ResultMapping>集合, 是one-to-many关系 。 元素"select|insert|update|delete"将会被解析为MappedStatement对象,该对象包含了ParameterMap、 ResultMap等对象。 1. 解析 parameterMap元素 (Made In Visual Paradigm) MapperBuilderAssistant是一个通用构建Mapper辅助类。 ParameterMapping.Builder用于构建 ParameterMapping对象,而ParameterMap.Builder则用于构建 ParameterMap对象。 其中resolveTypeHandler()很重要,我们自定义的 TypeHandler要起作用,就靠该方法正确绑定 TypeHandler了,后续会单独开一篇关于

Mybatis3.4.x技术内幕(十九):Mybatis之plugin插件设计原理

偶尔善良 提交于 2019-11-27 08:34:12
大多数框架,都支持插件,用户可通过编写插件来自行扩展功能,Mybatis也不例外。 我们从插件配置、插件编写、插件运行原理、插件注册与执行拦截的时机、初始化插件、分页插件的原理等六个方面展开阐述。 1. 插件配置 Mybatis的插件配置在configuration内部,初始化时,会读取这些插件,保存于Configuration对象的InterceptorChain中。 <?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> <plugins> <plugin interceptor="com.mybatis3.interceptor.MyBatisInterceptor"> <property name="value" value="100" /> </plugin> </plugins> </configuration> public class Configuration { protected final InterceptorChain interceptorChain = new

Mybatis3.3.x技术内幕(十五):Mybatis之foreach批量insert,返回主键id列表(修复Mybatis返回null的bug)

被刻印的时光 ゝ 提交于 2019-11-27 08:33:06
Mybatis在执行批量插入时,如果使用的是for循环逐一插入,那么可以正确返回主键id。如果使用动态sql的foreach循环,那么返回的主键id列表,可能为null,这让很多人感到困惑;本文将分析问题产生的原因,并修复返回主键id为null的问题。该问题在开源中国社区,以及网络上,已经有很多人遇到并发帖咨询,似乎都没有得到期望的解决结果。今天,我将带领大家,分析并解决该问题,让foreach批量插入,返回正确的id列表。 <insert id="insertStudents" useGeneratedKeys="true" keyProperty="studId" parameterType="java.util.ArrayList"> INSERT INTO STUDENTS(STUD_ID, NAME, EMAIL, DOB, PHONE) VALUES <foreach collection="list" item="item" index="index" separator=","> (#{item.studId},#{item.name},#{item.email},#{item.dob}, #{item.phone}) </foreach> </insert> 以上便是Mybatis的foreach循环,其要生成的sql语句是:insert into

Mybatis3.3.x技术内幕(十四):Mybatis之KeyGenerator

非 Y 不嫁゛ 提交于 2019-11-26 20:36:20
在Mybatis中,执行insert操作时,如果我们希望返回数据库生成的自增主键值,那么就需要使用到KeyGenerator对象。 需要注意的是,KeyGenerator的作用,是返回数据库生成的自增主键值,而不是生成数据库的自增主键值。返回的主键值放到哪儿呢?放到parameter object的主键属性上。 下面看看其接口定义。 public interface KeyGenerator { void processBefore(Executor executor, MappedStatement ms, Statement stmt, Object parameter); void processAfter(Executor executor, MappedStatement ms, Statement stmt, Object parameter); } 接口定义还是比较简单的,就是在insert前、insert后,策略处理主键值。 (Made In IntelliJ IDEA IDE) Jdbc3KeyGenerator:用于处理数据库支持自增主键的情况,如MySQL的auto_increment。 NoKeyGenerator:空实现,不需要处理主键。 SelectKeyGenerator:用于处理数据库不支持自增主键的情况,比如Oracle的sequence序列。

Mybatis3.3.x技术内幕(六):StatementHandler(Box stop here)

倖福魔咒の 提交于 2019-11-26 20:36:04
神通广大的猴哥SqlSession,把琐事委托给二弟Executor来处理,二弟Executor可不那么傻,于是它又把事情委托给三弟StatementHandler,三弟憨厚老实,本着 Box stop here 的精神,无怨无悔不说,还任劳任怨,于是,一代伟人就此诞生了。 三弟 StatementHandler从跑龙套开始,逐渐崛起,先后担任武术指导、制片、监制等职位,最后,经验丰富的它当上了导演,拍了属于自己的作品:三弟电影,又称3D电影。 有关 Box stop here 的故事,请自行了解。 1. 数据库操作invoke时序图 (Made In Visual Paradigm) 本文重点分析StatementHandler和ParameterHandler是如何与Executor共襄盛举的。( 上图中的execute()失误画错了,应该是executeQuery() ) 2. Executor内使用 StatementHandler模板 Statement stmt; StatementHandler handler; // 判断缓存内是否存在stmt if (...) { // 不存在,就创建一个Statement(可能是Statement、PrepareStatement、CallableStatement) stmt = handler.prepare

Mybatis3.3.x技术内幕(一):SqlSession和SqlSessionFactory列传

旧巷老猫 提交于 2019-11-26 20:35:48
前言:我长大了,成年了,有需求,但我单身,所以我要讨个媳妇,要求是:漂亮、高挑、身材好、笑容甜美…… 和A相亲:漂亮,不够高挑。 和B相亲:高挑,身材不够好。 和C相亲:身材好,笑容不够甜美。 …… 好烦,没有符合要求的,我是一个痛苦的完美主义者,我怒了,我决定依照完美的幻想,自己造一个。但不知道我的决定是对是错,请佛指点,佛面带慈祥的微笑,曰:你不造一个,谁造一个? 于是,造之前,我给她取了一个清新典雅的名字: Mybatis3.3.x技术内幕 。 wocao,好耳熟的名字,好像在哪儿听过。 以上便是面对已有的那么多有关Mybatis源码分析的文章,而我为什么决定新造一个“ 东风铁甲 ”的故事。 一部经典的《Mybatis3.3.x技术内幕》,就从SqlSession和SqlSessionFactory说起。 ‍ 1. SqlSession和 SqlSessionFactory的接口定义 ‍ SqlSession: public interface SqlSession extends Closeable { <T> T selectOne(String var1); <T> T selectOne(String var1, Object var2); <E> List<E> selectList(String var1); <E> List<E> selectList

Mybatis3.3.x技术内幕(五):Executor之doFlushStatements()

我们两清 提交于 2019-11-26 20:35:08
这天气,热的我满头大蒜。 在上一篇博文 ‍ ‍ ‍ ‍ 《五鼠闹东京之执行器Executor设计原本》 ‍ ‍ ‍ ‍ 中,已经对 Executor做了比较详细的分析,但是,测试妹纸阅读完后,表示某些地方看不懂,毫不客气的给我提出了两点修改意见。 一、看完你的Statement和PrepareStatement批处理原理图,依然不明白为何一个编译Sql 3次,而另外一个编译Sql 1次。 二、对关闭Statement对象一笔带过,不够清晰。 我准备亡羊补牢,针对上面的两个问题进行补充完善。 1.Statement和PrepareStatement在批处理时对Sql的编译策略 insert into students(id) values(1); insert into students(id) values(1); insert into students(id) values(2); insert into students(id) values(3); 上面的4个Sql,无论是Statement,还是PrepareStatement,对Sql都编译3次。因为其中第1、2条Sql是完全相同的,只会编译1次。 insert into students(id) values(?); // id=[1,2,3] 对于 PrepareStatement,支持问号“?”占位符