Data Access 之 MyBatis Plus(四)- MyBatis Plus Plugin

简介: Data Access 之 MyBatis Plus(四)- MyBatis Plus Plugin

一、MyBatis 的插件机制

MyBatis Plus的插件机制也是基于MyBatis的插件机制;MyBatis通过插件Interceptor可以拦截四大组件相关方法的执行,完成相关数据的动态改变。这里所提到的MyBatis中的四大组件既:

  • Executor
  • StatementHandler
  • ParameterHandler
  • ResultSetHandler

这四个组件在创建时都会执行interceptorChain.pluginAll()方法,该方法会循环调用拦截器列表中每一个拦截器的plugin()方法,该方法会为四大组件创建并返回代理对象,从而可以通过代理对象进行方法拦截,达到增强目标方法的目的

以StatementHandler为例,BaseStatementHandler抽象类实现类StatementHandler接口,

c0cd1d4d84c5439a9fbb76633599dd32_tplv-k3u1fbpfcp-zoom-in-crop-mark_4536_0_0_0.png

BaseStatmentHandler包含了一个构造方法,构造方法中包含了parameterHandler属性,该属性通过newParameterHandler()方法创建

6d8ccd8b68e14629bb68f1d9daa18cd9_tplv-k3u1fbpfcp-zoom-in-crop-mark_4536_0_0_0.png

这里就是调用了pluginAll()方法

54df2d7d15b049cabdf29c63ba8c486c_tplv-k3u1fbpfcp-zoom-in-crop-mark_4536_0_0_0.png

循环所有的拦截器,调用拦截器的plugin()方法,返回代理对象

3fe33127cb24472d98e94a8a6c7d796f_tplv-k3u1fbpfcp-zoom-in-crop-mark_4536_0_0_0.png

创建工程

拷贝mybatis-plus-mpg项目重命名为mybatis-plus-interceptor

二、MyBatis Plus PaginationInnerInterceptor插件

MP的分页插件是PaginationInnerInterceptor,该接口实现了InnerInterceptor接口,MyBatisPlusInterceptor实现了Interceptor接口,MyBatisPlusInterceptor接口包含了一个InnerInterceptorList属性

7fc19351beb34bf38b2b05dbc900f4b9_tplv-k3u1fbpfcp-zoom-in-crop-mark_4536_0_0_0.png

并且实现类Interceptor接口的plugin()方法,plugin()方法中有调用了wrap()方法,该方法通过反射生成代理对象

c0cd131fbf6549f0bc10d50e849f29cb_tplv-k3u1fbpfcp-zoom-in-crop-mark_4536_0_0_0.png

这也就是为什么配置分页插件时要先配置一个InnerInterceptor

<!--配置分页插件-->
<bean id="paginationInnerInterceptor" class="com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor">
    <property name="dbType" value="MYSQL"></property>
</bean>
复制代码

再配置一个Interceptor,并引用上面配置的InnerInterceptor

<!--配置拦截器-->
<bean id="mybatisPlusInterceptor" class="com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor">
    <property name="interceptors" ref="paginationInnerInterceptor"></property>
</bean>
复制代码

最后再将Interceptor配置到SQLSessionFactoryBean中

<!--替换为MyBatis-Plus的MyBatisSqlSessionFactoryBean,原来是MyBatis的SqlSessionFactoryBean-->
<bean id="mybatisSqlSessionFactoryBean" class="com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean">
    <!--设置使用分页插件,否则分页会失效-->
    <property name="plugins" ref="mybatisPlusInterceptor"></property>
</bean>
复制代码

在TeslaMapperTest中增加方法

@Test
public void testPage(){
    Page<Tesla> page = new Page<>(2, 4);
    Page<Tesla> teslaPage = teslaMapper.selectPage(page, null);
    System.out.println("获取总记录数:" + teslaPage.getRecords().size());
}
复制代码

selectPage()方法会返回一个Page对象,这个Page对象中包含分页相关的信息

System.out.println("----Page对象的属性和方法----");
System.out.println("获取总记录数:" + teslaPage.getTotal());
System.out.println("获取当前页面的记录:" + teslaPage.getRecords());
System.out.println("是否有下一页:" + teslaPage.hasNext());
System.out.println("是否有上一页:" + teslaPage.hasPrevious());
System.out.println("总页数为:" + teslaPage.getPages());
System.out.println("当前页数为:" + teslaPage.getCurrent());
System.out.println("当前页记录数为:" + teslaPage.getSize());
复制代码

c6864cb7ae1f42a4a0d3b6c87edbdc56_tplv-k3u1fbpfcp-zoom-in-crop-mark_4536_0_0_0.png

三、MyBatis Plus BlockAttackInnerInterceptor 防止全表更新与删除

在MP 3.4.0 版本之后SqlExplainInterceptor插件被删除,BlockAttackInnerInterceptor可以替代SQLExplainInterceptor来实现防止全表更新与删除的功能,具体可以参考官网 MyBatis Plus 插件主体

BlockAttackInnerInterceptor的作用是分析DELETE和UPDATE语句防止全表更新或者全表删除,适用于MySQL 5.6 版本以上,并且只建议在开发环境使用,不建议在生产环境使用

配置 BlockAttackInnerInterceptor 插件

配置interceptors拦截器列表,将分页插件和BlockAttackInnerInterceptor一起配置到mybatisPlusInterceptor的interceptors属性中,通过list标签来配置

<!--配置拦截器-->
<bean id="mybatisPlusInterceptor" class="com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor">
    <property name="interceptors">
        <list>
            <!--配置分页插件-->
            <bean id="paginationInnerInterceptor" class="com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor">
                <property name="dbType" value="MYSQL"></property>
            </bean>
            <!--防止全表更新删除插件-->
            <bean id="blockAttackInnerInterceptor" class="com.baomidou.mybatisplus.extension.plugins.inner.BlockAttackInnerInterceptor">
            </bean>
        </list>
    </property>
</bean>
复制代码

测试插件

@Test
public void testBlockAttackInnerInterceptor(){
    // 全表删除
    teslaMapper.delete(null);
}
复制代码

689224eb272e490fb083c4e1899be665_tplv-k3u1fbpfcp-zoom-in-crop-mark_4536_0_0_0.png

SQL执行失败,成功阻止了全表删除操作,也可以参考官方文档中BlockAttackInnerInterceptor 的使用方式

四、MyBatis Plus IllegalSQLInnerInterceptor 不规范SQL拦截器插件

IllegalSQLInnerInterceptor插件可以对不规范的SQL进行拦截

<!--配置拦截器-->
<bean id="mybatisPlusInterceptor" class="com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor">
    <property name="interceptors">
        <list>
            <bean id="illegalSQLInnerInterceptor" class="com.baomidou.mybatisplus.extension.plugins.inner.IllegalSQLInnerInterceptor">
            </bean>
        </list>
    </property>
</bean>
复制代码

再次执行testPage()方法

25fbc8c49bc946f887cfdc988d07bc7c_tplv-k3u1fbpfcp-zoom-in-crop-mark_4536_0_0_0.png

此时会报错,因为SQL语句中没有WHERE关键字

该插件会拦截的SQL语句类型为:

  • 必须使用到索引,包含left join连接字段,符合索引最左原则
  • 如果因为动态SQL,bug导致update的where条件没有带上,全表更新上万条数据
  • 如果检查到使用了索引,SQL性能基本不会太差
  • SQL尽量单表执行,有查询left join的语句,必须在注释里面允许该SQL运行,否则会被拦截,有left join的语句,如果不能拆成单表执行的SQL,请leader商量在做,SQL尽量单表执行的好处:
  • 查询条件简单、易于开理解和维护
  • 扩展性极强;(可为分库分表做准备)
  • 缓存利用率高
  • where条件为空、!=、包含not、or、子查询,都会拦截

五、MyBatis Plus OptimisticLockerInnerInterceptor 乐观锁插件

什么是乐观锁?

乐观锁是对于数据冲突保持一种乐观态度,操作数据时不会对操作的数据进行加锁(这使得多个任务可以并行的对数据进行操作),只有到数据提交的时候才通过一种机制来验证数据是否存在冲突(一般实现方式是通过加版本号然后进行版本号的对比方式实现);

如果想实现如下需求,既当要更新一条记录时,希望这条记录没有被别人更新

乐观锁的实现原理:

  • 取出记录时,获取当前的version
  • 更新时带上这个version
  • 执行更新时 version在原来的基础上+1
  • 如果version不一致,更新失败

配置乐观锁插件

<!--配置拦截器-->
<bean id="mybatisPlusInterceptor" class="com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor">
    <property name="interceptors">
        <list>
            <!--其他插件配置省略-->
            <!--乐观锁插件-->
            <bean id="optimisticLockerInnerInterceptor" class="com.baomidou.mybatisplus.extension.plugins.inner.OptimisticLockerInnerInterceptor">
            </bean>
        </list>
    </property>
</bean>
复制代码

给Tesla实体类添加Integer类型的version字段,并添加@Version注解,数据库表中添加对应的version中字段

TeslaMapperTest中增加测试代码

@Test
public void testOptimisticLockerInnerInterceptor(){
    // 更新操作
    Tesla tesla = new Tesla();
    tesla.setId(1166057518);
    tesla.setName("Model 3 2022");
    tesla.setPrice(280000.00);
    tesla.setVehicleType("四门轿车");
    tesla.setFactory("上海工厂");
    tesla.setVersion(1);
    teslaMapper.updateById(tesla);
}
复制代码

eae3a7e8f82c410a9a0860b096cbb6f6_tplv-k3u1fbpfcp-zoom-in-crop-mark_4536_0_0_0.png

更新条件多了一个version字段,并且更新之后数据库中version字段从1变为2,

tesla.setFactory("上海工厂");
复制代码

重新setFactory之后再次执行测试,此时代码中的version字段和数据库中的字段已经不一致

af33e6881af3402488a5941f5f8010d8_tplv-k3u1fbpfcp-zoom-in-crop-mark_4536_0_0_0.png

更新函数为0,更新失败


相关文章
|
2月前
|
Java 数据库连接 mybatis
Springboot整合Mybatis,MybatisPlus源码分析,自动装配实现包扫描源码
该文档详细介绍了如何在Springboot Web项目中整合Mybatis,包括添加依赖、使用`@MapperScan`注解配置包扫描路径等步骤。若未使用`@MapperScan`,系统会自动扫描加了`@Mapper`注解的接口;若使用了`@MapperScan`,则按指定路径扫描。文档还深入分析了相关源码,解释了不同情况下的扫描逻辑与优先级,帮助理解Mybatis在Springboot项目中的自动配置机制。
139 0
Springboot整合Mybatis,MybatisPlus源码分析,自动装配实现包扫描源码
|
3月前
|
SQL XML Java
springboot整合mybatis-plus及mybatis-plus分页插件的使用
这篇文章介绍了如何在Spring Boot项目中整合MyBatis-Plus及其分页插件,包括依赖引入、配置文件编写、SQL表创建、Mapper层、Service层、Controller层的创建,以及分页插件的使用和数据展示HTML页面的编写。
springboot整合mybatis-plus及mybatis-plus分页插件的使用
|
4月前
|
Java 数据库连接 mybatis
成功解决: Invalid bound statement (not found) 在已经使用mybatis的项目里引入mybatis-plus,结果不能共存的解决
这篇文章讨论了在已使用MyBatis的项目中引入MyBatis-Plus后出现的"Invalid bound statement (not found)"错误,并提供了解决方法,主要是通过修改yml配置文件来解决MyBatis和MyBatis-Plus共存时的冲突问题。
成功解决: Invalid bound statement (not found) 在已经使用mybatis的项目里引入mybatis-plus,结果不能共存的解决
|
5月前
|
Java 数据库连接 测试技术
mybatis plus 获取新增实体的主键
mybatis plus 获取新增实体的主键
155 8
|
5月前
|
Java 数据库连接 数据库
mybatis plus 更新值为null的字段
mybatis plus 更新值为null的字段
60 7
|
5月前
|
Java 数据库连接 Spring
搭建 spring boot + mybatis plus 项目框架并进行调试
搭建 spring boot + mybatis plus 项目框架并进行调试
96 4
|
5月前
|
SQL Java 数据库连接
idea中配置mybatis 映射文件模版及 mybatis plus 自定义sql
idea中配置mybatis 映射文件模版及 mybatis plus 自定义sql
95 3
|
5月前
|
Java 数据库连接 数据库
mybatis plus 中增删改查及Wrapper的使用
mybatis plus 中增删改查及Wrapper的使用
225 3
|
5月前
|
算法 Java 数据库连接
mybatis plus 主键策略
mybatis plus 主键策略
56 2
|
2月前
|
Java 数据库连接 Maven
mybatis使用一:springboot整合mybatis、mybatis generator,使用逆向工程生成java代码。
这篇文章介绍了如何在Spring Boot项目中整合MyBatis和MyBatis Generator,使用逆向工程来自动生成Java代码,包括实体类、Mapper文件和Example文件,以提高开发效率。
120 2
mybatis使用一:springboot整合mybatis、mybatis generator,使用逆向工程生成java代码。