Mybatis动态SQL处理过程
动态SQL的定义动态 SQL 是 MyBatis 的强大特性之一。动态SQL的概念是指在MyBatis中使用条件逻辑构建的SQL语句,这些SQL语句在运行时根据传入的参数动态改变。动态SQL允许开发者在XML映射文件或使用注解的方式中,根据不同的条件组合出不同的SQL语句,从而避免了为每种可能的查询条件编写单独的SQL语句,提高了代码的复用性和灵活性。
如果一段SQL不包含动态逻辑,那么我们称它为静态SQL,比如:
1SELECT * FROM USER WHERE ID = #{id}
反之,如果一段SQL包含以下任意一个或多个元素,那么它就是动态SQL:
<if>:根据条件判断是否包含某段SQL。
<choose>、<when>、<otherwise>:多分支选择,类似于Java中的switch语句。
<where>:智能地插入WHERE关键字,并且能够处理其后的AND或OR关键字。
<set>:智能地插入SET关键字,并且能够处理列表末尾的逗号。
<foreach>:用于遍 ...
Mybatis嵌套映射机制原理
前言我们知道,在MySQL中的关联查询语法可以使我们获得一个来源于多表的包含多个字段列表,类似这样
id
TITLE
comment_id
comment_content
1
文章1
1
你说的对
1
文章1
2
写的太好了
前面两个字段是Blog表的字段,后面两个是评论表达字段。现在假设我们需要将这列表转换成博客对象包含评论集合的数据结构,类似这样:
1BlogPO(id=1, title=文章1, content=null, userId=null, comments=[CommentPO{id=1, blogId=null, userId=null, content='你说的对'}, CommentPO{id=2, blogId=null, userId=null, content='写的太好了'}])
当然我们完全可以用JAVA写转换逻辑,但其实Mybatis已经为我们提供了类似的功能,我们今天就看下这套机制的实现原理。
DEMO照例还是先写一个小例子
XML的配置
12345 ...
Mybatis的懒加载机制
懒加载定义什么是Mybatis的懒加载机制?简单来说就是在使用时才会触发查询操作,而不是在一开始就加载所有数据。懒加载机制只在有子查询时生效,一定程度上可以提升程序的响应能力。
懒加载的整体结构
测试程序还是基于Blog和Comment的测试程序,简单调整一下。
1234567891011121314151617181920212223242526<?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="org.example.mybatis_reader.mybatis.blog.BlogMapper"> <resultMap id="BlogMap ...
Mybatis延迟加载机制
A依赖B B又依赖A所构成的一种循环,也可以称为循环依赖,试想下这个场景在MyBatis中会怎样?如果不管的话那就是死循环了。
循环依赖流程
Mybatis是通过延迟加载来解决循环依赖问题的。
Demo实例在下面例子中,BlogMap中有评论信息,而评论信息中又反过来包含博客信息,两者互相依赖。
123456789101112131415161718192021222324252627<?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="org.example.mybatis_reader.mybatis.blog.BlogMapper"> <cache/& ...
Mybatis之PreparedStatementHandler源码解读
StatementHandler的整体结构PreparedStatementHandler实现自StatementHandler,我们先看下StatementHandler的结构
StatementHandler的执行流程
请求参数处理所谓的请求参数处理,就是将入参转换为JDBC参数的过程。主要分为两个步骤,一是参数的转换,二是参数的映射。
参数的转换如果是单个参数,我们的请求参数会被转换为一个Object对象;如果是多个请求参数,或者单个参数但是被加了@Param注解,那么我们的入参是会被转换成Map。举个例子:
12@Select("SELECT * FROM T_USER WHERE id = #{user.id} OR USER_NAME = #{name}")UserPO selectUserWithPo(@Param("user") UserPO userPO, @Param("name") String name);
参数转换的源码如下:
1234567891011 ...
Mybatis的二级缓存机制
二级缓存的定义MyBatis的二级缓存是一个全局的缓存,与一级缓存只作用域会话级别不同,它的作用范围是整个应用,二级缓存可以跨线程使用。所以二级缓存有更高的命中率,适合缓存一些修改较少的数据。
开启二级缓存可以在*mapper.xml中添加一行,或者在Mapper接口上添加@CacheNamespace注解以获取二级缓存的支持。
开启二级缓存后可以获得以下效果(摘自官网)
映射语句文件中的所有 select 语句的结果将会被缓存。
映射语句文件中的所有 insert、update 和 delete 语句会刷新缓存。
缓存会使用最近最少使用算法(LRU, Least Recently Used)算法来清除不需要的缓存,总共支持以下几种淘汰策略:
LRU – 最近最少使用:移除最长时间不被使用的对象。
FIFO – 先进先出:按对象进入缓存的顺序来移除它们。
SOFT – 软引用:基于垃圾回收器状态和软引用规则移除对象。
WEAK – 弱引用:更积极地基于垃圾收集器状态和弱引用规则移除对
缓存不会定时进行刷新(也就是说,没有刷新间隔)。
缓存会保存列表或对象(无论查询方法返回哪种)的 ...
Mybatis的一级缓存机制
一级缓存先声明一个测试类FirstCacheTest,然后我们就可以在里面写测试方法了。
12345678910111213141516import org.apache.ibatis.session.SqlSession;import org.apache.ibatis.session.SqlSessionFactory;import org.apache.ibatis.session.SqlSessionFactoryBuilder;import org.junit.Before;import org.junit.Test;public class FirstCacheTest { private SqlSession sqlSession; @Before public void init() { SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder(); SqlSessionFactory sqlSessi ...
Mybatis图解执行器
一张图了解Mybatis执行器
SqlSession内部维护了一个Executor类,这里是CachingExecutor,所以SqlSession内部会调用CachingExecutor的query()方法执行查询流程
CachingExecutor内部有一个被声明为Executor类的delegate属性,在完成内部的二级缓存操作后,它会调用BaseExecutor的query()方法
BaseExecutor会做一些公共的事情,比如一级缓存的处理,获取链接等等,它也不会真的执行查询数据的操作,而是调用子类的doQuery()、doUpdate()去执行数据库查询操作
子类执行数据库查询逻辑,子类有SimpleExecutor、ReuseExecutor、BatchExecutor,还有一个ClosedExecutor,由于它和前面三个做的事情完全不同,所以不再解释它。
SqlSession默认情况下是DefaultSqlSession,操作数据动作是调用的CachingExecutor.query()方法。
123456789101112131415161718192021p ...
Mybatis阅读源码的前置准备工作
版本信息
Spring Boot 3.3.0
Mybatis 3.5.16
JDK 17
Demo搭建搭建一个简单的Spring Boot项目,方便调试Mybatis源码。
首先创建一个Spring Boot的项目,我这里将项目命名为Mybatis_Reader,并引入相关依赖。
设置依赖12345678910111213141516171819202122232425262728293031323334353637383940414243<dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId ...
SpringCloud之Resilience4j的断路器机制详解
前言断路器是一种服务保护机制,断路器通过有限状态机实现,有三个普通状态:关闭、开启、半开,还有两个特殊状态:禁用、强制开启。断路器默认是关闭状态,当满足条件时断路器会处于打开状态,此时不会再继续请求下游服务而是直接返回熔断逻辑。在一定时间后断路器会变成半开状态,这种状态下允许部分请求通过,然后依据这部分请求的结果判定断路器是转换为关闭还是打开。
状态的流转如下图所示:
断路器使用滑动窗口来存储和统计调用的结果。你可以选择基于调用数量的滑动窗口或者基于时间的滑动窗口。
基于访问数量的滑动窗口基于访问数量的滑动窗口是通过一个有N个元素的循环数组实现。
如果滑动窗口的大小等于10,那么循环数组总是有10个统计值。滑动窗口增量更新总的统计值,随着新的调用结果被记录在环形数组中,总的统计值也随之进行更新。当环形数组满了,时间最久的元素将被驱逐,将从总的统计值中减去该元素的统计值,并该元素所在的桶进行重置。
基于时间的滑动窗口基于时间的滑动窗口是通过有N个桶的环形数组实现。
如果滑动窗口的大小为10秒,这个环形数组总是有10个桶,每个桶统计了在这一秒发生的所有调用的结果(部分统计结果),数组中的 ...