HuKai's Blog HuKai's Blog
首页
  • Java核心技术

    • Java基础
    • Java并发编程
    • JVM
    • Java新特性
  • Spring生态

    • Spring5
    • SpringMVC
    • SpringBoot
  • 开源框架

    • MyBatis
  • 计算机网络
  • 操作系统
  • 数据结构与算法
  • 设计模式
  • SQL数据库

    • MySQL
    • Oracle
  • NoSQL数据库

    • Redis
    • MongoDB
  • 页面样式

    • HTML
    • CSS
  • JavaScript

    • JavaScript基础
    • ECMAScript6教程
    • TypeScript
  • 前端框架

    • Vue
    • Webpack
  • NIO
  • Netty
  • RabbitMQ
  • 技术文档

    • GitHub技巧
    • 博客搭建
    • 技术笔记
  • 优质文章

    • 小技巧
    • 解决方案
GitHub (opens new window)

HuKai

梦想成为全栈的保安
首页
  • Java核心技术

    • Java基础
    • Java并发编程
    • JVM
    • Java新特性
  • Spring生态

    • Spring5
    • SpringMVC
    • SpringBoot
  • 开源框架

    • MyBatis
  • 计算机网络
  • 操作系统
  • 数据结构与算法
  • 设计模式
  • SQL数据库

    • MySQL
    • Oracle
  • NoSQL数据库

    • Redis
    • MongoDB
  • 页面样式

    • HTML
    • CSS
  • JavaScript

    • JavaScript基础
    • ECMAScript6教程
    • TypeScript
  • 前端框架

    • Vue
    • Webpack
  • NIO
  • Netty
  • RabbitMQ
  • 技术文档

    • GitHub技巧
    • 博客搭建
    • 技术笔记
  • 优质文章

    • 小技巧
    • 解决方案
GitHub (opens new window)
  • Java基础

  • Java并发编程

  • JVM

  • Java新特性

  • Spring5

  • SpringMVC

  • SpringBoot

  • MyBatis

    • 应用篇

      • MyBatis快速入门
      • MyBatis配置文件深入
      • MyBatis复杂映射开发
      • MyBatis缓存机制
      • MyBatis插件机制
        • 1. MyBatis插件介绍
        • 2. 自定义MyBatis插件
        • 3. 常用插件介绍
    • 源码篇

    • 扩展篇

  • Java
  • MyBatis
  • 应用篇
HuKai
2022-03-20
目录

MyBatis插件机制

# 1. MyBatis插件介绍

MyBatis作为一个应用广泛的优秀的ORM开源框架,这个框架具有强大的灵活性,在四大组件(Executor、StatementHandler、ParameterHandler、ResultsetHandler)处提供了简单易用的插件扩展机制。Mybatis对持久层的操作就是借助于四大核心对象。Mybatis支持用插件对四大核心对象进行拦截,对于Mybatis来说插件就是拦截器,用了增强核心对象的功能,增强功能本质上是借助于底层动态代理实现的,换句话说,MyBatis中的四大对象都是代理对象。

通过官网 (opens new window)可知,Mybatis插件机制允许拦截四大对象的方法如下:

  • Executor (update, query, flushStatements, commit, rollback, getTransaction, close, isClosed)
  • ParameterHandler (getParameterObject, setParameters)
  • ResultSetHandler (handleResultSets, handleOutputParameters)
  • StatementHandler (prepare, parameterize, batch, update, query)

# 2. 自定义MyBatis插件

在 MyBatis 中开发插件,需要实现 Interceptor 接口,接口的定义如下:

public interface Interceptor {

  Object intercept(Invocation invocation) throws Throwable;

  Object plugin(Object target);

  void setProperties(Properties properties);

}
1
2
3
4
5
6
7
8
9
  • intercept(Invocation invocation)方法:它将直接覆盖你所拦截对象原有的方法,因此它是插件的核心方法。通过 invocation 参数可以反射调度原来对象的方法。
  • plugin(Object target)方法:target 是被拦截对象,它的作用是给被拦截对象生成一个代理对象,并返回它。为了方便MyBatis 使用 org.apache.ibatis.plugin.Plugin 中的 wrap 静态方法提供生成代理对象。
  • setProperties(Properties properties)方法:允许在 plugin 元素中配置所需参数,方法在插件初始化的时候就被调用了一次,然后把插件对象存入到配置中,以便后面再取出。

我们现在来实现这个接口,对Executor对象的query方法进行拦截:

//注意看这个大花括号,也就这说这里可以定义多个@Signature对多个地方拦截,都用这个拦截器
@Intercepts({
        @Signature(type = Executor.class,//这是指拦截哪个接口
                method = "query",//这个接口内的哪个方法名,不要拼错了
                // 这是拦截的方法的入参,按顺序写到这,不要多也不要少,如果方法重载,可是要通过方法名和入参来确定唯一的
                args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class})
})
public class ExamplePlugin implements Interceptor {
    private final Logger logger = LoggerFactory.getLogger(this.getClass());

    //这里是每次执行操作的时候,都会进行这个拦截器的方法内
    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        System.out.println("------------------intercept方法执行开始--------------------");
        System.out.println("invocation.getTarget:"+invocation.getTarget().getClass().getName());
        for (Object arg : invocation.getArgs()) {
            System.out.println("参数:"+arg);
        }
        System.out.println("invocation.getMethod:"+invocation.getMethod().getName());
        return invocation.proceed();
    }

    //主要是为了把这个拦截器生成一个代理放到拦截器链中
    @Override
    public Object plugin(Object target) {
        System.out.println("------------------plugin方法执行开始--------------------");
        System.out.println("将要包装的目标对象:"+target);
        return Plugin.wrap(target,this);
    }

    //插件初始化的时候调用,也只调用一次,插件配置的属性从这里设置进来
    @Override
    public void setProperties(Properties properties) {
        System.out.println("------------------setProperties方法执行开始--------------------");
        System.out.println("插件配置的初始化参数:" + properties);
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37

自定义MyBatis插件必须加上@Intercepts注解,在@Intercepts内部可以定义多个@Signature对多个地方拦截。

配置SqlMapConfig.xmll文件:

<plugins>
    <plugin interceptor="com.hukai.demo.plugin.ExamplePlugin">
        <property name="name" value="hukai"/>
    </plugin>
</plugins>
1
2
3
4
5

这样Mybatis在启动时可以加载插件,并在调用相应方法时进行拦截,我们来看看效果:


# 3. 常用插件介绍

# 3.1 PageHelper分页插件

MyBatis可以使用第三方的插件来对功能进行扩展,分页助手PageHelper是将分页的复杂操作进行封装,使用简单的方式即可获得分页的相关数据。

开发步骤:

  • 导入通用PageHelper的坐标
<dependency>
    <groupId>com.github.pagehelper</groupId>
    <artifactId>pagehelper</artifactId>
    <version>3.7.5</version>
</dependency>
<dependency>
    <groupId>com.github.jsqlparser</groupId>
    <artifactId>jsqlparser</artifactId>
    <version>0.9.1</version>
</dependency>
1
2
3
4
5
6
7
8
9
10
  • 在mybatis核心配置文件中配置PageHelper插件
<!--注意:分页助手的插件 配置在通用馆mapper之前-->
<plugin interceptor="com.github.pagehelper.PageHelper">
    <!--指定方言 -->
    <property name="dialect" value="mysql"/>
</plugin>
1
2
3
4
5
  • 测试分页代码实现
@Test
public void testFindAll() {
    Page pageInfo = PageHelper.startPage(1, 10);
    List<Emp> empList = empMapper.findAll();
    empList.forEach(System.out::println);
	//  System.out.println("总条数:"+pageInfo.getTotal());
	//  System.out.println("总页数:"+pageInfo. getPages ());
	//  System.out.println("当前页:"+pageInfo. getPageNum());
	//  System.out.println("每页显示长度:"+pageInfo.getPageSize());
}
1
2
3
4
5
6
7
8
9
10

# 3.2 通用Mapper

通用Mapper就是为了解决单表增删改查,基于Mybatis的插件机制。开发人员不需要编写SQL,不需要在Mapper接口中增加方法,只要写好实体类,就能支持相应的增删改查方法。

开发步骤:

  • 首先在maven项目,在pom.xml中引入mapper的依赖。
<dependency>
    <groupId>tk.mybatis</groupId>
    <artifactId>mapper</artifactId>
    <version>3.1.2</version>
</dependency>
1
2
3
4
5
  • Mybatis配置文件中完成配置
<plugin interceptor="tk.mybatis.mapper.mapperhelper.MapperInterceptor"> 
    <!-- 通用Mapper接口,多个通用接口用逗号隔开 -->
    <property name="mappers" value="tk.mybatis.mapper.common.Mapper"/>
</plugin>
1
2
3
4
  • 实体类设置主键
@Table(name = "t_user")
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer id;
    private String username;
}
1
2
3
4
5
6
7
  • 定义通用mapper
import tk.mybatis.mapper.common.Mapper;
	public interface UserMapper extends Mapper<User> {
}
1
2
3
  • 测试代码
public class UserTest {
    @Test
    public void test1() throws IOException {
        Inputstream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");
        SqlSessionFactory build = new SqlSessionFactoryBuilder().build(resourceAsStream);
        SqlSession sqlSession = build.openSession();
        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
        User user = new User();
        user.setId(4);
        //(1)mapper基础接口
        //select 接口
        User user1 = userMapper.selectOne(user); //根据实体中的属性进行查询,只能有一个返回值
        List<User> users = userMapper.select(null); //查询全部结果
        userMapper.selectByPrimaryKey(1); //根据主键字段进行查询,方法参数必须包含完整的主键属性,查询条件使用等号
        userMapper.selectCount(user); //根据实体中的属性查询总数,查询条件使用等号
        // insert 接口
        int insert = userMapper.insert(user); //保存一个实体,null值也会保存,不会使用数据库默认值
        int i = userMapper.insertSelective(user); //保存实体,null的属性不会保存会使用数据库默认值
        // update 接口
        int i1 = userMapper.updateByPrimaryKey(user);//根据主键更新实体全部字段,null值会被更新
        // delete 接口
        int delete = userMapper.delete(user); //根据实体属性作为条件进行删除,查询条件 使用等号
        userMapper.deleteByPrimaryKey(1); //根据主键字段进行删除,方法参数必须包含完 整的主键属性
        //(2)example方法
        Example example = new Example(User.class);
        example.createCriteria().andEqualTo("id", 1);
        example.createCriteria().andLike("val", "1");
        //自定义查询
        List<User> users1 = userMapper.selectByExample(example);
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
编辑 (opens new window)
#MyBatis
上次更新: 2022/03/20, 16:39:15
MyBatis缓存机制
MyBatis源码剖析-数据处理

← MyBatis缓存机制 MyBatis源码剖析-数据处理→

最近更新
01
MyBatisPlus
03-20
02
MyBatis源码剖析-延迟加载
03-20
03
MyBatis源码剖析-二级缓存
03-20
更多文章>
Theme by Vdoing | Copyright © 2021-2022 HuKai | 赣ICP备17016768号
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式