MyBatisPlus系列第六篇:插件扩展

一、MyBatis插件机制简介

1、插件机制

Mybatis通过插件(Intercept)可以做到拦截四大对象相关方法的执行,根据需求,完成相关数据的动态改变。

Excutor

StatementHandler

ParameterHandler

ResultSetHandler

2、插件原理

四大对象的每个对象在创建时,都会执行interceptChain.pluginAll()、会经过每个插件对象的plugin()方法,目的是为当前的四大对象创建代理。代理对象就可以拦截到四大对象相关方法的执行,因为要执行四大对象方法需要经过代理

二、分页插件

1、mybatis-config.xml全局配置文件中配置

    <!-- 注册插件property 属性会被插件的获取到-->
    <plugins>
        <plugin interceptor="com.ming.plugin.MyPlugin">
            <property name="username" value="root"/>
            <property name="password" value="123456"/>
        </plugin>
    </plugins>

2、spring整合mybatis,在MybatisSqlSessionFactoryBean进行配置

    <!--  配置SqlSessionFactoryBean
        Mybatis提供的: org.mybatis.spring.SqlSessionFactoryBean
        MP提供的:com.baomidou.mybatisplus.spring.MybatisSqlSessionFactoryBean
     -->
    <bean id="sqlSessionFactoryBean" class="com.baomidou.mybatisplus.spring.MybatisSqlSessionFactoryBean">
        <!-- 数据源 -->
        <property name="dataSource" ref="dataSource"></property>
        <property name="configLocation" value="classpath:mybatis-config.xml"></property>
        <!-- 别名处理 -->
        <property name="typeAliasesPackage" value="com.ming.mp.beans"></property>

        <!-- 注入全局MP策略配置 -->
        <property name="globalConfig" ref="globalConfiguration"></property>

        <!--注册插件-->
        <property name="plugins">
            <!--分页插件注册-->
           <list>
               <bean class="com.baomidou.mybatisplus.plugins.PaginationInterceptor"></bean>
           </list>
        </property>
    </bean>
package com.ming.mp.test;

import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.baomidou.mybatisplus.plugins.Page;
import com.ming.mp.beans.Employee;
import com.ming.mp.mapper.EmployeeMapper;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import java.util.Arrays;
import java.util.List;

/**
 * 分页插件测试
 */
public class TestPage {

    ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");

    EmployeeMapper mapper = context.getBean("employeeMapper", EmployeeMapper.class);

    @Test
    public void testPaginationInterceptor() {

        List<Employee> employeeList = mapper.selectPage(new Page<Employee>(1, 1), new EntityWrapper<Employee>().orderDesc(Arrays.asList("1")));
        employeeList.stream().forEach(System.out::print);
    }

}

package com.ming.service;

import com.baomidou.mybatisplus.extension.service.IService;
import com.ming.bean.User;
import com.ming.util.PageResult;

public interface IUserService extends IService<User> {

    PageResult findPage(int pageNum,int pageSize);
}



https://www.cnblogs.com/xifengxiaoma/p/11027551.html

package com.ming.service.impl;

import com.alibaba.druid.sql.PagerUtils;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.ming.bean.User;
import com.ming.mapper.UserMapper;
import com.ming.service.IUserService;
import com.ming.util.PageResult;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;

@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService {
    @Autowired
    UserMapper userMapper;

    @Override
    public PageResult findPage(int pageNum, int pageSize) {
        PageHelper.startPage(pageNum, pageSize);
        List<User> list = userMapper.selectList(null);
        PageInfo<User> pageInfo = new PageInfo<>(list);
        PageResult pageResult = PageResult.getPageResult(pageInfo);
        return pageResult;
    }
}

package com.ming.util;

import com.github.pagehelper.PageInfo;
import lombok.Data;

import java.util.List;

@Data
public class PageResult {
    /**
     * 当前页码
     */
    private int pageNum;
    /**
     * 每页数量
     */
    private int pageSize;
    /**
     * 总条数
     */
    private long totalSize;
    /**
     * 页码总数
     */
    private int totalPages;
    /**
     * 返回的数据集合
     */
    private List<?> Data;


    /**
     * 处理分页结果集
     *
     * @param pageInfo
     * @return
     */
    public static PageResult getPageResult(PageInfo<?> pageInfo) {
        PageResult pageResult = new PageResult();
        pageResult.setPageNum(pageInfo.getPageNum());
        pageResult.setPageSize(pageInfo.getPageSize());
        pageResult.setTotalSize(pageInfo.getTotal());
        pageResult.setTotalPages(pageInfo.getPages());
        pageResult.setData(pageInfo.getList());
        return pageResult;
    }
}

package com.jinnjo.goods.utils;

import org.springframework.data.domain.Pageable;

import java.util.ArrayList;
import java.util.List;

/**
 * 功能描述
 * 手动分页
 * @author subingbing
 * 2018/8/23
 */
public class ManualPageableUtil {
    public static  <T> List<T> backPageList(List<T> source, Pageable pageable, Integer totalElements){
        if(source.size() > 0) {
            List<T> dest = new ArrayList<>();
            Integer pageSize = pageable.getPageSize();
            Integer pageNumber = pageable.getPageNumber();
            int length = (pageNumber + 1) * pageSize<=totalElements?(pageNumber + 1) * pageSize:totalElements;
            for (int i = pageNumber * pageSize; i < length; i++) {
                dest.add(source.get(i));
            }
            return dest;
        }else{
            return source;
        }
    }
}

三、执行分析插件

1、com.baomidou.mybatisplus.plugins.SqlExplainInterceptor

2、SQL 执行分析拦截器,只支持 MySQL5.6.3 以上版本

3、 该插件的作用是分析 DELETE UPDATE 语句,防止小白或者恶意进行 DELETE UPDATE 全表操作

4、只建议在开发环境中使用,不建议在生产环境使用

5、在插件的底层 通过 SQL 语句分析命令:Explain 分析当前的SQL 语句,根据结果集中的 Extra 列来断定当前是否全表操作

注册执行分析插件

    <!--  配置SqlSessionFactoryBean
        Mybatis提供的: org.mybatis.spring.SqlSessionFactoryBean
        MP提供的:com.baomidou.mybatisplus.spring.MybatisSqlSessionFactoryBean
     -->
    <bean id="sqlSessionFactoryBean" class="com.baomidou.mybatisplus.spring.MybatisSqlSessionFactoryBean">
        <!-- 数据源 -->
        <property name="dataSource" ref="dataSource"></property>
        <property name="configLocation" value="classpath:mybatis-config.xml"></property>
        <!-- 别名处理 -->
        <property name="typeAliasesPackage" value="com.ming.mp.beans"></property>

        <!-- 注入全局MP策略配置 -->
        <property name="globalConfig" ref="globalConfiguration"></property>

        <!--注册插件-->
        <property name="plugins">
           <list>
               <!--分页插件注册-->
               <bean class="com.baomidou.mybatisplus.plugins.PaginationInterceptor"></bean>
               <!--注册执行分析插件-->
               <bean class="com.baomidou.mybatisplus.plugins.SqlExplainInterceptor">
                   <!--作用就是我发现了当前你的操作是全表删除或更新、会阻止你的操作-->
                   <property name="stopProceed" value="true"/>
               </bean>
           </list>

        </property>
    </bean>

debug查看源码


    /**
     * 执行分析插件
     * 
     */
    @Test
    public void  explainTest(){
        mapper.delete(null);
    }

PaginationInterceptor进行debug可以看出是执行的SQL分析sqlExplain

四、性能分析插件

1、 com.baomidou.mybatisplus.plugins.PerformanceInterceptor

2、性能分析拦截器,用于输出每条 SQL 语句及其执行时间

3、SQL 性能执行分析,开发环境使用 , 超过指定时间,停止运行。有助于发现问题

    <!--  配置SqlSessionFactoryBean
        Mybatis提供的: org.mybatis.spring.SqlSessionFactoryBean
        MP提供的:com.baomidou.mybatisplus.spring.MybatisSqlSessionFactoryBean
     -->
    <bean id="sqlSessionFactoryBean" class="com.baomidou.mybatisplus.spring.MybatisSqlSessionFactoryBean">
        <!-- 数据源 -->
        <property name="dataSource" ref="dataSource"></property>
        <property name="configLocation" value="classpath:mybatis-config.xml"></property>
        <!-- 别名处理 -->
        <property name="typeAliasesPackage" value="com.ming.mp.beans"></property>

        <!-- 注入全局MP策略配置 -->
        <property name="globalConfig" ref="globalConfiguration"></property>

        <!--注册插件-->
        <property name="plugins">
           <list>
               <!--分页插件注册-->
               <bean class="com.baomidou.mybatisplus.plugins.PaginationInterceptor"></bean>
               <!--注册执行分析插件-->
               <bean class="com.baomidou.mybatisplus.plugins.SqlExplainInterceptor">
                   <!--作用就是我发现了当前你的操作是全表删除或更新、会阻止你的操作-->
                   <property name="stopProceed" value="true"/>
               </bean>
               <!--注册性能分析插件-->
               <bean class="com.baomidou.mybatisplus.plugins.PerformanceInterceptor">
                   <!--SQL是否格式化-->
                   <property name="format" value="true"></property>

                   <property name="maxTime" value="100"></property>
               </bean>
           </list>

        </property>
    </bean>
    /**
     * 测试性能分析插件
     */
    @Test
    public void testPerformanceInterceptor() {
        Employee employee = new Employee();
        employee.setLastName("MP");
        employee.setEmail("1111111@qq.com");
        employee.setAge(18);
        employee.setGender("1");
        mapper.insert(employee);
    }

五、乐观锁插件

1、 com.baomidou.mybatisplus.plugins.OptimisticLockerInterceptor

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

3、乐观锁的实现原理:取出记录时,获取当前 version 2更新时,带上这个 version 2执行更新时, set version = yourVersion+1 where version = yourVersion 如果 version 不对,就更新失败

4、 @Version 用于注解实体字段,必须要有。

乐观锁插件

	<!--  配置SqlSessionFactoryBean
	Mybatis提供的: org.mybatis.spring.SqlSessionFactoryBean
	MP提供的:com.baomidou.mybatisplus.spring.MybatisSqlSessionFactoryBean
	-->
    <bean id="sqlSessionFactoryBean" class="com.baomidou.mybatisplus.spring.MybatisSqlSessionFactoryBean">
        <!-- 数据源 -->
        <property name="dataSource" ref="dataSource"></property>
        <property name="configLocation" value="classpath:mybatis-config.xml"></property>
        <!-- 别名处理 -->
        <property name="typeAliasesPackage" value="com.ming.mp.beans"></property>

        <!-- 注入全局MP策略配置 -->
        <property name="globalConfig" ref="globalConfiguration"></property>

        <!--注册插件-->
        <property name="plugins">
           <list>
               <!--分页插件注册-->
               <bean class="com.baomidou.mybatisplus.plugins.PaginationInterceptor"></bean>
               <!--注册执行分析插件-->
               <bean class="com.baomidou.mybatisplus.plugins.SqlExplainInterceptor">
                   <!--作用就是我发现了当前你的操作是全表删除或更新、会阻止你的操作-->
                   <property name="stopProceed" value="true"/>
               </bean>
               <!--注册性能分析插件-->
               <bean class="com.baomidou.mybatisplus.plugins.PerformanceInterceptor">
                   <!--SQL是否格式化-->
                   <property name="format" value="true"></property>

                   <property name="maxTime" value="100"></property>
               </bean>
               <!--乐观锁插件-->
               <bean class="com.baomidou.mybatisplus.plugins.OptimisticLockerInterceptor">
               </bean>
           </list>

        </property>
    </bean>

实体类和数据库添加version字段并用@version注解

    @Version
    private Integer version;

如果version版本不一样更新失败


    /**
     * 测试乐观锁插件
     */
    @Test
    public void testOptimisticLockerInterceptor() {
        Employee employee = new Employee();
        employee.setId(15);
        employee.setLastName("TOM_B");
        employee.setEmail("11111117997798@qq.com");
        employee.setAge(18);
        employee.setGender("1");
        employee.setVersion(1);
        mapper.updateById(employee);
    }

    /**
     * 测试乐观锁插件 单线程下修改成功
     */
    @Test
    public void testOptimisticLockerInterceptor2() {
        //1.查出用户version信息  Preparing: SELECT id,last_name AS lastName,email,gender,age,version FROM tbl_employee WHERE id=?
        Employee employee = mapper.selectById(1);
        //2.修改用户UPDATE tbl_employee SET last_name=?, email=?, gender=?, version=? WHERE id=? and version=?
        employee.setLastName("测试乐观锁");
        employee.setEmail("aaa@qq.com");
        //3.执行更新操作
        mapper.updateById(employee);
    }

    /**
     * 测试乐观锁插件 单线程下修改成功
     */
    @Test
    public void testOptimisticLockerInterceptor3() {
        // 线程1
        Employee employee = mapper.selectById(1);
        employee.setLastName("测试乐观锁111");
        employee.setEmail("aaa@qq.com");
        //模拟另外一个线程执行了插队操作
        Employee employee2 = mapper.selectById(1);
        employee2.setLastName("测试乐观锁222");
        employee2.setEmail("aaa@qq.com");
        //自旋锁来多次尝试提交
        mapper.updateById(employee2);//如果没有乐观锁就会覆盖插队线程的值
        mapper.updateById(employee);
    }
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值