07_Mybatis-Plus_插件扩展
Mybatis插件机制简介
插件机制:
Mybatis通过插件(Interceptor)可以做到拦截四大对象相关方法的执行,根据需求,完成数据的动态改变。
- Executor
- StatementHandler
- ParamerterHandler
- ResultSetHandler
插件原理:
四大对象的每个对象在创建的时候,都会执行interceptorChain.pluginAll(),会经过每个插件对象的plugin()方法,目的是为当前的四大对象创建代理。代理对象就可以拦截到四大对象相关的方法的执行,因为要执行四大对象的方法需要经过代理。
分页插件
com.baomidou.mybatisplus.plugins.PaginationInterceptor
在spring配置文件的mybatis配置中添加:
测试:
相关代码:
public class TestMP {
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
EmployeeMapper employeeMapper = ctx.getBean("employeeMapper",EmployeeMapper.class);
/**
* 测试分页插件
* @throws Exception
*/
@Test
public void testPage() throws Exception {
List emps = employeeMapper.selectPage(new Page(1, 1), null);
System.out.println(emps);
}
}
输出日志:
DEBUG 06-15 15:25:34,428 ==> Preparing: SELECT COUNT(1) FROM tbl_employee (BaseJdbcLogger.java:159)
DEBUG 06-15 15:25:34,452 ==> Parameters: (BaseJdbcLogger.java:159)
DEBUG 06-15 15:25:34,484 ==> Preparing: SELECT id AS id,last_name AS lastName,email,gender,age FROM tbl_employee LIMIT 0,1 (BaseJdbcLogger.java:159)
DEBUG 06-15 15:25:34,485 ==> Parameters: (BaseJdbcLogger.java:159)
DEBUG 06-15 15:25:34,489 <== Total: 1 (BaseJdbcLogger.java:159)
控制台输出:
[Employee{, id=1, lastName=Tom, [email protected], gender=1, age=22}]
可以看到是有物理分页效果的,LIMIT子句。
分页后Page对象的使用
相关代码:
public class TestMP {
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
EmployeeMapper employeeMapper = ctx.getBean("employeeMapper",EmployeeMapper.class);
/**
* 测试分页插件
* @throws Exception
*/
@Test
public void testPage() throws Exception {
Page page = new Page(1,1);
List emps = employeeMapper.selectPage(page, null);
System.out.println("---------------");
System.out.println("总条数:"+page.getTotal());
System.out.println("当前页码:"+page.getCurrent());
System.out.println("总页码:"+page.getPages());
System.out.println("每页显示的条数:"+page.getSize());
System.out.println("是否有上一页:"+page.hasPrevious());
System.out.println("是否有下一页:"+page.hasNext());
// 将查询的结果封装到page对象中
page.setRecords(emps);
System.out.println(page.getRecords());
}
}
控制台输出:
总条数:6
当前页码:1
总页码:6
每页显示的条数:1
是否有上一页:false
是否有下一页:true
[Employee{, id=1, lastName=Tom, [email protected], gender=1, age=22}]
执行分析插件
- com.baomidou.mybatisplus.plugins.SqlExplainInterceptor
- SQL执行分析拦截器,只支持MySQL5.6.3以上版本
- 该插件的作用是分析DELETE、UPDATE语句,防止小白或者恶意进行DELTE、UPDATE全表操作
- 只建议在开发环境中使用,不建议在生产环境使用
- 在插件的底层通过SQL语句分析命令:Explain分析当前的SQL语句,根据结果集中的Extra列来断定当前是否全表操作
首先在Spring配置文件中需要加入执行分析插件:
日志输出:
WARN 06-15 15:50:16,300 Warn: Your mysql version needs to be greater than '5.6.3' to execute of Sql Explain! (SqlExplainInterceptor.java:80)
DEBUG 06-15 15:50:16,319 ==> Preparing: DELETE FROM tbl_employee (BaseJdbcLogger.java:159)
DEBUG 06-15 15:50:16,345 ==> Parameters: (BaseJdbcLogger.java:159)
DEBUG 06-15 15:50:16,349 <== Updates: 6 (BaseJdbcLogger.java:159)
由于本机使用的版本不是5.6.3以上的,所以没能成功。
若正常情况,则会报错,表示你正在执行删除全表操作。
原理是使用MySQL中的EXPLAIN
关键字,如EXPLAIN DELETE FROM tbl_employee,执行后有个Extra字段,结果可能是Deleting all rows或者Using where等,如果分析出不是Using where,则抛出异常。
性能分析插件
- com.baomidou.mybatisplus.plugins.PerformanceInterceptor
- 性能分析拦截器,用于输出每条SQL语句以及其执行时间
- SQL性能执行分析,开发环境使用,超过指定时间,停止运行,有利于发现问题
首先在Spring配置文件中注册插件:
日志输出会多出这段红色的文本:
正常输出:
Time:16 ms - ID:top.tomxwd.mp.mapper.EmployeeMapper.insert
Execute SQL:
INSERT
INTO
tbl_employee
( last_name, email, gender, age )
VALUES
( '12', '[email protected]', '1', 22 )]
超时输出:
未起作用。。。
否则会报错,超时异常。
乐观锁插件
- com.baomidou.mybatisplus.plugins.OptimisticLockerInterceptor
- 如果想实现如下需求:
- 当要更新一条记录的时候,希望这条记录没有被别人更新
- 乐观锁的实现原理:
- 取出记录的时候,获取当前version
- 更新时,带上这个version
- 执行更新时,set version = yourVersion+1 where version = yourVersion
- 如果version不对,就更新失败
- @Version用于注解实体字段,必须要有
首先注册插件:
加一个字段表示version。
加一个属性表示version,并打上@Version注解。
相关代码:
/**
* 测试 乐观锁插件
* @throws Exception
*/
@Test
public void testOptimisticLocker() throws Exception {
// 更新操作
Employee emp = new Employee();
emp.setId(13);
emp.setLastName("test");
emp.setVersion(1);
employeeMapper.updateById(emp);
}
日志输出:
DEBUG 06-15 19:32:47,513 ==> Preparing: UPDATE tbl_employee SET last_name=?, version=? WHERE id=? and version=? (BaseJdbcLogger.java:159)
DEBUG 06-15 19:32:47,550 ==> Parameters: test(String), 2(Integer), 13(Integer), 1(Integer) (BaseJdbcLogger.java:159)
DEBUG 06-15 19:32:47,553 <== Updates: 1 (BaseJdbcLogger.java:159)
重点关注sql语句:UPDATE tbl_employee SET last_name=?, version=? WHERE id=? and version=?
以及参数的值test(String), 2(Integer), 13(Integer), 1(Integer)
- 发现version不但被更新,并且在where条件中。
- 发现set的version值为2,而where的version值为1,说明在对象设置属性值的时候,version指的是数据库里的版本。