赞
踩
MyBatis
允许你在已映射语句执行过程中的某一点进行拦截调用。默认情况下,MyBatis
允许使用插件来拦截的方法调用包括:
Executor (update, query, flushStatements, commit, rollback, getTransaction, close, isClosed)
ParameterHandler (getParameterObject, setParameters)
ResultSetHandler (handleResultSets, handleOutputParameters)
StatementHandler (prepare, parameterize, batch, update, query)
总体概括为:
我们看到了可以拦截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:
在Mybatis-Plus
中提供了对SQL
执行的分析的插件,可用作阻断全表更新、删除的操作,注意:该插件仅适用于开发环境,不适用于生产环境。
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源码查看
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); } }
运行结果:
性能分析拦截器,用于输出每条 SQL
语句及其执行时间,可以设置最大执行时间,超过时间会抛出异常。
和执行分析插件一样,该插件只用于开发环境,不建议生产环境使用。
说明:我最开始用的Mybatis-Plus 3.3.2
,发现没有PerformanceInterceptor类。于是我把Mybatis-Plus
版本降到了 3.1.0
。然后就可以正常使用性能分析插件了。
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); } }
运行结果:
异常情况补充:
上面一直使用的代码注入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
当要更新一条记录的时候,希望这条记录没有被别人更新
乐观锁实现方式:
version
version
set version = newVersion where version = oldVersion
version
不对,就更新失败配置文件方式:
<!--乐观锁插件-->
<plugin interceptor="com.baomidou.mybatisplus.extension.plugins.OptimisticLockerInterceptor"/>
spring boot代码注入Bean的方式:
MybatisPlusConfig.java
@Bean
public OptimisticLockerInterceptor optimisticLockerInterceptor() {
return new OptimisticLockerInterceptor();
}
需要为实体字段添加@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注解:
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。Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。