mybtais mybatisplus TkMybatis 原理
所属分类 mybatis
浏览量 122
Mybatis源码分析
解析过程
根据mybatis-config.xml创建通过SqlSessionFactoryBuilder创建SqlSessionFactory对象
通过XPathParser解析器来帮助解析xml
XMLConfigBuilder解析config.xml
XMLMapperBuilder解析Mapper.xml
XMLStatementBuilder解析select等sql语句
最终的语句包装类为MappedStatement
SqlSessionFactory对象其中包含一个完整的Configuration对象
Configuration对象中的字段mappedStatements保存语句,key为类路径+sql的Id
sqlSessionFactory.getConfiguration().getMappedStatementNames();
["org.demo.dao.mapper.PetMapper.queryPets","queryPets"]
mapperRegistry保存所有解析的Mapper接口
每次向mapperRegistry中添加Mapper接口时,会尝试查找相同包名下的mapper.xml文件
执行过程
通过SqlSessionFactory对象创建SqlSession对象,具体类型为DefaultSqlSession
其中包含一个执行器Executor,经过了拦截器的处理
通过SqlSession对象获取Mapper对象,底层使用JDK动态代理
拦截器为MapperProxy对象
通过方法获取一个MapperMethod对象,其中包含MappedStatement
通过MappedStatement创建一个BoundSql对象
BoundSql对象包含要执行的sql和参数等信息
创建一个StatementHandler,其中通过DefaultParameterHandler来设置参数
最终通过PreparedStatement执行
通过DefaultResultSetHandler来处理返回值,先处理列名属性自动映射,再处理配置的ResultMap,具体逻辑在 getRowValue() 方法。
关于SQL语句中的${}和#{}的处理
MappedStatement中包含一个SqlSource对象
DynamicSqlSource
RawSqlSource
ProviderSqlSource
StaticSqlSource
RawSqlSource 只有 #{} 或者 没有标签的纯文本sql信息
DynamicSqlSource 包含 ${} 或者 具有动态sql标签的sql信息
StaticSqlSource 是DynamicSqlSource和RawSqlSource解析为BoundSql的一个中间环节
在MappedStatement获取BoundSql对象时,会将#{}转换成?,并将之前的SqlSource对象转换成StaticSqlSource类型。
对于${}的处理(需要手动加单引号),具体处理类为TextSqlNode的apply()方法,拼接SQL(通过OGNL表达式获取属性值),
对于#{}的处理,是PreparedStatement设置参数(防止SQL注入)。
orderby只能使用${}。
SqlSourceBuilder来解析#{uname,jdbcType=VARCHAR}这种表达式语法。
select * from tb_user where u_name like '${uname}'; -- 需要加单引号
select * from tb_user where u_name like #{uname};
关于默认参数名称
select * from tb_user where u_name like #{param1} and u_age = #{param2};
具体处理类为ParamNameResolver
关于like的使用
select * from tb_user where u_name like concat('%', #{uname}, '%');
需要在 sql 中拼接 % 或者代码中拼接 %
懒加载
Configuration的lazyLoadingEnabled字段,默认false,proxyFactory默认使用JavassistProxyFactory创建代理,也支持Cglib。
在创建ResultMap时可能使用。
缓存
一级缓存:BaseExecutor的localCache字段,内部为HashMap,同一个SqlSession(因为不同的SqlSession包含不同的Executor)。
默认开启,增删改会清空缓存。
二级缓存:SqlSessionFactory级别
< settings>
settings>
< cache />
存储在Configuration的caches字段中,key为Mapper.xml的namespace
也会存储到MappedStatement的cache字段中
主要是TransactionalCacheManager的transactionalCaches字段来管理,
key为Cache类型,value为TransactionalCache类型(包装了Cache),必须commit之后缓存才实际保存到Cache中。
入口类为CachingExecutor。
从MappedStatement中获取Cache对象
根据此对象从TransactionalCacheManager中获取对应的TransactionalCache
查询是否有缓存值
有则直接返回,没有走一级缓存的流程
保存到TransactionalCache对象中
commit之后,保存到TransactionalCache中的delegate字段中,实际是委托它来存储的。
分页插件 pagehelper
< plugins>
< plugin interceptor="com.github.pagehelper.PageInterceptor" />
PageHelper.startPage(1,2);
将分页信息保存到ThreadLocal中,实际上是一个Page对象。
拦截BaseExecutor的query()方法
生成一个count的sql并执行(通过jsqlparser解析原来的sql)
将查询得到的数据总数量count也保存到Page中
对原来的查询SQL拼接分页信息,如mysql拼接limit
将查询得到的list结果也保存到Page中
最终返回的就是Page对象
整合SpringBoot
mybatis-spring-boot-starter
配置Mapper.xml路径
mybatis.mapper-locations=classpath:mapper/*Mapper.xml
配置Mapper接口扫描包路径
@SpringBootApplication
@MapperScan("com.xxx.mybatis")
或者对Mapper接口添加@Mapper注解,最终创建的Mapper实现类为MapperFactoryBean
会自动装配MybatisAutoConfiguration,自动配置SqlSessionFactory,SqlSessionTemplate,
最终使用的 SqlSession 实现为动态代理,拦截器为 SqlSessionInterceptor
@MapperScan
ClassPathMapperScanner 将Mapper接口的实现(MapperFactoryBean)注入了Spring容器中
原理图
https://gitee.com/dyyx/work2024/tree/master/docs/mybatis/images/
mybatis001.webp mybatis002.webp mybatis003.webp
MybatisPlus源码分析
解析过程
使用MybatisSqlSessionFactoryBuilder替代原来的SqlSessionFactoryBuilder
使用MybatisXMLConfigBuilder替代原来的XMLConfigBuilder
使用MybatisConfiguration替代Configuration
使用MybatisMapperRegistry替代MapperRegistry
使用MybatisMapperProxyFactory替代MapperProxyFactory
使用MybatisMapperProxy替代MapperProxy
使用MybatisMapperAnnotationBuilder替代MapperAnnotationBuilder
使用GlobalConfig保存全局配置
如果接口类是com.baomidou.mybatisplus.core.mapper.Mapper的子类,
使用ISqlInjector注入动态SQL的实现,可以自定义自己的SQL注入器
执行过程
使用MybatisCachingExecutor替代CachingExecutor
重写query()方法,支持分页查询
使用PaginationInterceptor插件
拦截BaseStatementHandler的prepare()方法
生成一个count的SQL
使用拦截的方法参数 执行count的SQL
MybatisPlus默认开启类名和表名的转换(属性和列名),驼峰转下划线,具体处理类为TableInfoHelper
特性
内置通用mapper,可以很方便的实现单表的大部分增删改查操作。
PaginationInterceptor用来处理类型为IPage的参数,MybatisMapperMethod用来处理返回类型为IPage的返回值
MetaObjectHandler用来在insert或update时自动设置属性值,
配合注解@TableField的fill字段使用,在MybatisParameterHandler处理参数时生效。
注解@TableLogic,标注此注解的属性,调用内置的删除方法时,不是真正的delete,而是update,内置select时默认加上此条件。
注解@EnumValue,配合MybatisEnumTypeHandler处理器
IPage< User> findByPage(IPage< User> page); //页码从1开始
TkMybatis源码分析
解析过程
MapperAutoConfiguration开启自动配置,在MybatisAutoConfiguration之前生效
定义SqlSessionFactory和SqlSessionTemplate
使用注解@tk.mybatis.spring.annotation.MapperScan 替代 @org.mybatis.spring.annotation.MapperScan
它的解析类MapperScannerRegistrar内部使用新的
tk.mybatis.spring.mapper.ClassPathMapperScanner替代老的org.mybatis.spring.mapper.ClassPathMapperScanner
将Mapper接口的实现类替换为 tk.mybatis.spring.mapper.MapperFactoryBean,
代替老的 org.mybatis.spring.mapper.MapperFactoryBean
新的MapperFactoryBean重写了checkDaoConfig()方法,处理配置的子接口
mapper.mappers=tk.mybatis.mapper.common.Mapper
获取方法上的SelectProvider,UpdateProvider,DeleteProvider,InsertProvider注解信息,
生成SqlSource对象,并设置到MappedStatement对象中
接口继承 tk.mybatis.mapper.common.Mapper接口 拥有增强功能
本质上利用了mybatis本身提供的Provider功能(通过Provider来自定义sql)
通过 EntityHelper 来解析 javax.persistence 包下的 @Table,@Id,@Column等注解,
保存实体类和表结构的映射关系,功能类似 mybatisplus 的 TableInfoHelper 类
上一篇
下一篇
小红书视频下载
羽毛球新手学习顺序
mybtais 动态sql注解
java final 字段 反射修改说明
煎荷包蛋小技巧
mac brew 安装 openjdk17