MyBatis-Plus执行SQL分析打印
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了MyBatis-Plus执行SQL分析打印相关的知识,希望对你有一定的参考价值。
参考技术A 1、本文资料来自 MyBatis-Plus官网2、该功能依赖 p6spy 组件,完美的输出打印 SQL 及执行时长 3.1.0 以上版本
3、 示例工程
Mybatis-Plus:插件(mybatis的插件机制执行分析插件性能分析插件乐观锁插件)
1. mybatis的插件机制
MyBatis
允许你在已映射语句执行过程中的某一点进行拦截调用。默认情况下,MyBatis
允许使用插件来拦截的方法调用包括:
Executor (update, query, flushStatements, commit, rollback, getTransaction, close, isClosed)
ParameterHandler (getParameterObject, setParameters)
ResultSetHandler (handleResultSets, handleOutputParameters)
StatementHandler (prepare, parameterize, batch, update, query)
总体概括为:
- 拦截执行器的方法
- 拦截参数的处理
- 拦截结果集的处理
- 拦截Sql语法构建的处理
我们看到了可以拦截Executor
接口的部分方法,比如update
,query
,commit
,rollback
等方法,还有其他接口的一些方法等。
拦截器示例:
MyInterceptor.java
package com.tian.plugins;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.plugin.*;
import java.util.Properties;
@Intercepts(@Signature(
// 要拦截的是 Executor 执行器的 update方法
type = Executor.class,
method = "update",
args = MappedStatement.class, Object.class))
public class MyInterceptor implements Interceptor
@Override
//拦截方法,具体业务逻辑编写的位置 现在是只有update方法会进入该方法
public Object intercept(Invocation invocation) throws Throwable
return invocation.proceed(); // invocation.proceed()是放行
@Override
// 执行sql都会进入该方法 并且会执行4次 因为有4个处理器
/*
1. Executor (update, query, flushStatements, commit, rollback, getTransaction, close, isClosed) 拦截执行器的方法
2. ParameterHandler (getParameterObject, setParameters) 拦截参数的处理
3. ResultSetHandler (handleResultSets, handleOutputParameters) 拦截结果集的处理
4. StatementHandler (prepare, parameterize, batch, update, query) 拦截Sql语法构建的处理
*/
public Object plugin(Object target)
// 创建target对象的代理对象,目的是将当前拦截器加入到该对象中
return Plugin.wrap(target, this);
@Override
public void setProperties(Properties properties)
//属性设置
将拦截器注入到Spring容器:
MybatisPlusConfig.java
package com.tian.springbootmybatisplus;
import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor;
import com.tian.plugins.MyInterceptor;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
@MapperScan("com.tian.mapper") //设置mapper接口的扫描包
public class MybatisPlusConfig
@Bean //配置分页插件
public PaginationInterceptor paginationInterceptor()
return new PaginationInterceptor();
/*** 自定义拦截器 */
@Bean
public MyInterceptor myInterceptor()
return new MyInterceptor();
或者通过xml配置,mybatis-config.xml:
2. 执行分析插件(阻断全表更新、删除的操作)
在Mybatis-Plus
中提供了对SQL
执行的分析的插件,可用作阻断全表更新、删除的操作,注意:该插件仅适用于开发环境,不适用于生产环境。
2.1 配置
MyInterceptor.java
@Bean //SQL分析插件
public SqlExplainInterceptor sqlExplainInterceptor()
SqlExplainInterceptor sqlExplainInterceptor = new SqlExplainInterceptor();
List<ISqlParser> list = new ArrayList<>();
// 攻击 SQL 阻断解析器、加入解析链
list.add(new BlockAttackSqlParser()); //全表更新、删除的阻断器
sqlExplainInterceptor.setSqlParserList(list);
return sqlExplainInterceptor;
BlockAttackSqlParser.java源码查看
2.2 测试
SpringbootMybatisplusApplicationTests.java
package com.tian.springbootmybatisplus;
import com.tian.mapper.UserMapper;
import com.tian.pojo.User;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
class SpringbootMybatisplusApplicationTests
@Autowired
private UserMapper userMapper;
@Test
public void testUpdate()
User user = new User();
user.setAge(20);
// 把所有人的age设置为20
int result = this.userMapper.update(user, null);
System.out.println("result = " + result);
运行结果:
3. 性能分析插件
性能分析拦截器,用于输出每条 SQL
语句及其执行时间,可以设置最大执行时间,超过时间会抛出异常。
和执行分析插件一样,该插件只用于开发环境,不建议生产环境使用。
说明:我最开始用的Mybatis-Plus 3.3.2
,发现没有PerformanceInterceptor类。于是我把Mybatis-Plus
版本降到了 3.1.0
。然后就可以正常使用性能分析插件了。
3.1 Spring Boot 配置
MybatisPlusConfig.java
@Bean
// SQL 执行性能分析,开发环境使用,线上不推荐。
public PerformanceInterceptor performanceInterceptor()
PerformanceInterceptor performanceInterceptor = new PerformanceInterceptor();
// maxTime 指的是 sql 最大执行时长, 单位为ms
performanceInterceptor.setMaxTime(100);
// SQL是否格式化 默认为true
performanceInterceptor.setFormat(true);
return performanceInterceptor;
编写测试用例:
SpringbootMybatisplusApplicationTests.java
package com.tian.springbootmybatisplus;
import com.tian.mapper.UserMapper;
import com.tian.pojo.User;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
class SpringbootMybatisplusApplicationTests
@Autowired
private UserMapper userMapper;
@Test
public void testSelectById()
User user = new User();
// 查询Id为2的用户
user.setId(2L);
User user1 = user.selectById();
System.out.println(user1);
运行结果:
异常情况补充:
3.2 配置文件方式配置
上面一直使用的代码注入Bean
的方式去配置,现在我们来尝试着使用配置文件的方式去配置,这样可以练练手。
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>
<plugins>
<!-- 性能分析插件 -->
<plugin interceptor="com.baomidou.mybatisplus.extension.plugins.PerformanceInterceptor">
<!--最大的执行时间,单位为毫秒-->
<property name="maxTime" value="100"/>
<!--对输出的SQL做格式化,默认为false-->
<property name="format" value="true"/>
</plugin>
</plugins>
</configuration>
然后在SpringBoot
的全局配置文件指定Mybatis
的配置文件即可:
application.properties
# 指定全局的配置文件
mybatis-plus.config-location=classpath:mybatis-config.xml
4. 乐观锁插件
当要更新一条记录的时候,希望这条记录没有被别人更新
乐观锁实现方式:
- 取出记录时,获取当前
version
- 更新时,带上这个
version
- 执行更新时,
set version = newVersion where version = oldVersion
- 如果
version
不对,就更新失败
4.1 插件配置
配置文件方式:
<!--乐观锁插件-->
<plugin interceptor="com.baomidou.mybatisplus.extension.plugins.OptimisticLockerInterceptor"/>
spring boot代码注入Bean的方式:
MybatisPlusConfig.java
@Bean
public OptimisticLockerInterceptor optimisticLockerInterceptor()
return new OptimisticLockerInterceptor();
4.2 注解实体字段
需要为实体字段添加@Version
注解。
第一步,为表添加version字段,并且设置初始值为1:
Navicat
执行下面的sql
语句:
ALTER TABLE `tb_user` ADD COLUMN `version` int(10) NULL AFTER `email`; UPDATE `tb_user` SET `version`='1';
第二步,为User实体对象添加version字段,并且添加@Version注解:
4.3 测试
SpringbootMybatisplusApplicationTests.java
package com.tian.springbootmybatisplus;
import com.tian.mapper.UserMapper;
import com.tian.pojo.User;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
class SpringbootMybatisplusApplicationTests
@Autowired
private UserMapper userMapper;
@Test
public void testUpdate()
User user = new User();
user.setAge(30);
user.setId(2L);
user.setVersion(1); // 当前的version为1
int result = this.userMapper.updateById(user);
System.out.println("result = " + result);
运行结果:
生成的SQL语句为:
- 可以看到,更新的条件中有
version
条件,并且更新的version
为2。 - 如果再次执行,更新则不成功。这样就避免了多人同时更新时导致数据的不一致。
4.4 说明
以上是关于MyBatis-Plus执行SQL分析打印的主要内容,如果未能解决你的问题,请参考以下文章
springboot 打印 mybatis-plus 的sql