上一节我们学习了mybatis-plus
的代码生成器
,这一节我们来学习一下mybatis-plus
的插件拓展
。
首先我们来复习一下Mybatis 插件机制:
- 插件机制: Mybatis 通过插件(Interceptor) 可以做到拦截四大对象相关方法的执行,根据需求, 完成相关数据的动态改变。 Executor StatementHandler ParameterHandler ResultSetHandler
- 插件原理: 四大对象的每个对象在创建时,都会执行 interceptorChain.pluginAll(),会经过每个插件对象的 plugin()方法,目的是为当前的四大对象创建代理。代理对象就可以拦截到四大对象相关方法的执行,因为要执行四大对象的方法需要经过代理。
我们在mybatis-plus
这里学习三个插件,其他的插件看官可以自己自行尝试:
- 分页插件
- 执行分析插件
- 乐观锁插件
首先按照快速开始——Spring集成Mybatis-Plus
一节的操作,新建一个mp06
的 Module
,可以将mp05
中的内容全部复制过来。
修改mp06的pom.xml文件:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>mybatis-plus-in-action</artifactId>
<groupId>com.demo.mybatis-plus</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>mp06</artifactId>
<dependencies>
<!-- mp 依赖
mybatis-plus 会自动维护mybatis 以及 mybatis-spring相关的依赖
Mybatis 及 Mybatis-Spring 依赖请勿加入项目配置,以免引起版本冲突!!!Mybatis-Plus 会自动帮你维护!
-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus</artifactId>
<version>${mybatis.plus.version}</version>
</dependency>
<!--junit -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>${junit.version}</version>
</dependency>
<!-- log4j -->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>${log4j.version}</version>
</dependency>
<!-- druid -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>${druid.version}</version>
</dependency>
<!-- mysql -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>${mysql.version}</version>
</dependency>
<!-- spring -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-orm</artifactId>
<version>${spring.version}</version>
</dependency>
<!--lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring.version}</version>
</dependency>
<!--注意: MyBatis-Plus 从 3.0.3 之后移除了代码生成器与模板引擎的默认依赖,需要手动添加相关依赖: -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-generator</artifactId>
<version>${mybatis.plus.version}</version>
</dependency>
<!--模板引擎
MP 的代码生成器默认使用的是 Apache 的 Velocity 模板,当然也可以更换为别的模板
技术,例如 freemarker。此处不做过多的介绍。
需要加入 Apache Velocity 的依赖-->
<dependency>
<groupId>org.apache.velocity</groupId>
<artifactId>velocity-engine-core</artifactId>
<version>${velocity.version}</version>
</dependency>
<!--加入 slf4j ,查看日志输出信息-->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>${slf4j.version}</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>${slf4j.version}</version>
</dependency>
</dependencies>
</project>
下面我们需要根据不同的插件做的一些修改:
1、分页插件
其实在之前的分页查询代码示例中,我们已经展示了分页插件,不过当时并没有介绍,现在我们来详细介绍一下。
我们有两种配置方式可以实现分页的功能:
1.1、修改mybatis-config.xml文件,添加分页插件
<!-- 1、第一种方式,在 mybatis-config.xml 文件中引入分页插件-->
<plugins>
<plugin interceptor="com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor"></plugin>
</plugins>
完整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>
<!-- 1、第一种方式,在 mybatis-config.xml 文件中引入分页插件-->
<plugins>
<plugin interceptor="com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor"></plugin>
</plugins>
</configuration>
1.2、修改applicationContext.xml文件,添加分页插件
在sqlSessionFactory
这个bean中,通过<property name="plugins">
配置插件,接下来的所有插件都配置在这个list中
<!-- 2、第二种方式,在 applicationContext.xml 文件中引入分页插件-->
<property name="plugins">
<list>
<!-- 分页查询插件 -->
<bean id="paginationInterceptor"
class="com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor">
<property name="dialectType" value="mysql"/>
</bean>
</list>
</property>
1.3、测试分页插件
1.1和1.2的方式选择哪一种都可以实现分页的功能,现在我们在 TestMp
测试类中添加下面代码,来测试分页插件的功能
/**
* 测试分页插件
*/
@Test
public void testPage() {
IPage<Employee> employeeIPage = employeeMapper.selectPage(new Page<>(2, 1), null);
System.out.println("employeeIPage:" + employeeIPage.getRecords());
}
2、执行分析插件
该插件的作用是分析 DELETE UPDATE 语句,防止小白或者恶意进行 DELETE UPDATE 全表操作 。在插件的底层 通过 SQL 语句分析命令:Explain 分析当前的 SQL 语句, 根据结果集中的 Extra 列来断定当前是否全表操作。
注意
:只建议在开发环境中使用,不建议在生产环境使用 。SQL 执行分析拦截器,只支持 MySQL5.6.3 以上版本 。
2.2、修改applicationContext.xml文件,添加执行分析插件
<!-- 执行分析插件 只建议在开发环境中使用,不建议在生产环境使用 -->
<bean class="com.baomidou.mybatisplus.extension.plugins.SqlExplainInterceptor">
<property name="sqlParserList">
<!-- 禁止全表删除-->
<bean class="com.baomidou.mybatisplus.extension.parsers.BlockAttackSqlParser"></bean>
</property>
</bean>
2.2、测试执行分析插件
我们来进行一个全表删除来测试一下我们的执行分析插件,在测试类中添加下面的代码:
/**
* 测试 SQL 执行分析插件
*/
@Test
public void testSqlExplain() {
// 全表删除
employeeMapper.delete(null);
}
执行该方法后我们会看到测试方法执行失败,提示我们禁止全表的删除:
3、乐观锁插件
思考?如果想实现如下需求: 当要更新一条记录的时候,希望这条记录没有被别人更新 。当我们想实现上面的需求的时候,首先想到的是使用乐观锁机制。
乐观锁的实现原理: 1)取出记录时,获取当前 version 2)更新时,带上这个 version 3)执行更新时, set version = yourVersion+1 where version = yourVersion 如果 version 不对,就更新失败
3.1、修改applicationContext.xml文件,添加乐观锁插件
要想使用Mybatis-Plus
提供的乐观锁插件,首先需要修改applicationContext.xml文件,添加乐观锁插件
<!-- 乐观锁插件,做这个测试的时候,需要给实体类接一个version字段,相应的也需要在数据库中添加该字段 -->
<bean class="com.baomidou.mybatisplus.extension.plugins.OptimisticLockerInterceptor"></bean>
3.2、修改Employee实体类
修改Employee实体类,添加 version
字段,并添加getter、setter方法
@Version
private Integer version;
public Integer getVersion() {
return version;
}
public void setVersion(Integer version) {
this.version = version;
}
3.3、测试乐观锁插件
在测试类中添加下面的代码:
/**
* 测试 乐观锁
*/
@Test
public void testOptimisticLocker() {
Employee employee = new Employee();
employee.setId(10);
employee.setLastName("MP");
employee.setAge(25);
employee.setEmail("mp@qq.com");
employee.setGender("0");
employee.setVersion(2);
![mp06-02.png](https://upload-images.jianshu.io/upload_images/19878305-e8348cc75321c5f1.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
employeeMapper.updateById(employee);
}
执行该方法后我们会看到测试方法执行成功,更新时,带上这个 version,但更新的数据为0条,表示数据库中的数据并没有被更新,注意看我们的更新代码:
完成上面的操作后,mp06的完整applicationContext.xml
文件如下所示:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:mybatis-spring="http://mybatis.org/schema/mybatis-spring"
xsi:schemaLocation="http://mybatis.org/schema/mybatis-spring
http://mybatis.org/schema/mybatis-spring-1.2.xsd
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-4.0.xsd">
<!-- 数据源 -->
<context:property-placeholder location="classpath:db.properties"/>
<bean id="dataSource"
class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="${jdbc.driver}"></property>
<property name="url" value="${jdbc.url}"></property>
<property name="username" value="${jdbc.username}"></property>
<property name="password" value="${jdbc.password}"></property>
</bean>
<!-- 事务管理器 -->
<bean id="dataSourceTransactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!-- 基于注解的事务管理 -->
<tx:annotation-driven
transaction-manager="dataSourceTransactionManager"/>
<!-- 配置 SqlSessionFactoryBean
mybatis提供的:org.mybatis.spring.SqlSessionFactoryBean
mybatis-plus提供的:3.2.0 com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean
2.3 com.baomidou.mybatisplus.spring.MybatisSqlSessionFactoryBean
-->
<bean id="sqlSessionFactoryBean"
class="com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean">
<!-- 数据源 -->
<property name="dataSource" ref="dataSource"></property>
<property name="configLocation" value="classpath:mybatis-config.xml"></property>
<!-- 别名处理 -->
<property name="typeAliasesPackage" value="com.mp.beans"></property>
<!-- 注入配置-->
<!--<property name="configuration" ref="configuration"></property>-->
<!-- 注入全局配置策略-->
<property name="globalConfig" ref="globalConfiguration"></property>
<!-- 2、第二种方式,在 applicationContext.xml 文件中引入分页插件-->
<property name="plugins">
<list>
<!-- 分页查询插件 -->
<bean id="paginationInterceptor"
class="com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor">
<property name="dialectType" value="mysql"/>
</bean>
<!-- 执行分析插件 只建议在开发环境中使用,不建议在生产环境使用 -->
<bean class="com.baomidou.mybatisplus.extension.plugins.SqlExplainInterceptor">
<property name="sqlParserList">
<!-- 禁止全表删除-->
<bean class="com.baomidou.mybatisplus.extension.parsers.BlockAttackSqlParser"></bean>
</property>
</bean>
<!-- 乐观锁插件,做这个测试的时候,需要给实体类接一个version字段,相应的也需要在数据库中添加该字段 -->
<bean class="com.baomidou.mybatisplus.extension.plugins.OptimisticLockerInterceptor"></bean>
</list>
</property>
</bean>
<!--这个等于Mybatis的全局配置文件,如果在MybatisSqlSessionFactoryBean里面已经配置了configLocation属性(外部加载Mybatis全局配置文件),就不能再配置configuration属性-->
<bean id="configuration" class="com.baomidou.mybatisplus.core.MybatisConfiguration">
<!--开启驼峰命名-->
<property name="mapUnderscoreToCamelCase" value="true"/>
<!--日志打印SQL语句-->
<property name="logImpl" value="org.apache.ibatis.logging.log4j.Log4jImpl"></property>
</bean>
<!-- 定义mybatis-plus全局策略配置-->
<bean id="globalConfiguration" class="com.baomidou.mybatisplus.core.config.GlobalConfig">
<!-- 全局主键策略-->
<property name="dbConfig" ref="dbConfig"></property>
</bean>
<!-- 这里-->
<bean id="dbConfig" class="com.baomidou.mybatisplus.core.config.GlobalConfig$DbConfig">
<!-- 全局表主键生成策略 -->
<property name="idType" value="AUTO"></property>
<!-- 全局的表前缀策略配置 -->
<property name="tablePrefix" value="tbl_"></property>
</bean>
<!--
配置 mybatis 扫描 mapper 接口的路径
-->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage"
value="com.mp.mapper"></property>
</bean>
</beans>
mp06的代码结构如下所示:
至此,基于 mybatis-plus
的插件拓展
演示就完成了,下面我们就可以进入到下一节自定义全局操作和全局sql注入
的学习了。
源代码
相关示例完整代码:mybatis-plus-in-action
上一节:六、代码生成器——逆行工程
下一节:八、自定义全局操作和全局sql注入