Mybatis的插件机制、PageHelper分页插件的使用

一、插件的简介

1、简介

  • 与其称为Mybatis插件,不如叫Mybatis拦截器,更加符合其功能定位,
  • 实际上它就是一个拦截器,应用代理模式,在方法级别上进行拦截。

2、作用

  • 在四大对象创建的时候,都会进行拦截
  • 在四大方法创建之前&后,来做一些想做的事情(类似于AOP)
  • 插件会包每一个对象的创建过程
  • 四大对象:
    • 执行器Executor(update、query、commit、rollback等方法);
    • 参数处理器ParameterHandler(getParameterObject、setParameters方法);
    • 结果集处理器ResultSetHandler(handleResultSets、handleOutputParameters等方法);
    • SQL语法构建器StatementHandler(prepare、parameterize、batch、update、query等方法);

3、应用场景

  • 分页功能
    • mybatis的分页默认是基于内存分页的(查出所有,再截取),数据量大的情况下效率较低,不过使用mybatis插件可以改变该行为,只需要拦截StatementHandler类的prepare方法,改变要执行的SQL语句为分页语句即可;
  • 公共字段统一赋值
    一般业务系统都会有创建者,创建时间,修改者,修改时间四个字段,对于这四个字段的赋值,实际上可以在DAO层统一拦截处理,可以用mybatis插件拦截Executor类的update方法,对相关参数进行统一赋值即可;
  • 性能监控
    • 对于SQL语句执行的性能监控,可以通过拦截Executor类的update, query等方法,用日志记录每个方法执行的时间;
  • 其它
    • 其实mybatis扩展性还是很强的,基于插件机制,基本上可以控制SQL执行的各个阶段,如执行阶段,参数处理阶段,语法构建阶段,结果集处理阶段,具体可以根据项目业务来实现对应业务逻辑。

二、自定义插件

1、自定义插件的编写

插件的编写步骤:

   	 第一步: 实现Interceptor接口
  	 第二步:在实现类上配置 @Intercepts-->@Signature  指定要拦截的方法
  	 第三步:将写好的插件注册到全局配置文件中 <plugins>  -->  <pugin  >  -->  <property>
//配置要拦截的方法:
@Intercepts(
		{
				//可以配置多个连接的方法:type指定四大对象的哪个对象  method指定具体方法  args指定参数列表
				@Signature(type = StatementHandler.class,method = "parameterize",args = java.sql.Statement.class)
		}
)
public class MyFirstPlugin implements Interceptor {
	//拦截:拦截目标对象的目标方法(要拦截四大对象的哪个对象的哪个方法)
	public Object intercept(Invocation invocation) throws Throwable {

		//放行:执行目标方法
		Object proceed = invocation.proceed();
		//返回执行后的返回值
		return proceed;
	}

	//包装目标对象的方法
	public Object plugin(Object o) {
		//1、可以自己写一个动态代理进行包装
		//2、mybatis提供了一个包装的方法:第一个参数为要包装的内容,第二个为用哪个拦截器包装
		Object wrap = Plugin.wrap(o, this);
		//返回包装后的对象
		return wrap;
	}

	//将插件注册时的property属性注册进来
	public void setProperties(Properties properties) {
		//插件配置的信息
		System.out.println("插件配置的信息: "+properties);
	}
}

    <plugins>
        <plugin interceptor="com.zy.util.MyFirstPlugin" >
            <!-- 可以传入一些参数 -->
            <property name="username" value="root"/>
            <property name="password" value="123456"/>
        </plugin>
    </plugins>

2、多个插件的执行流程

会按照主配置文件中配置的顺序对 四大对象的某些方法 顺序包装

在这里插入图片描述

三、PageHelpler分页插件的使用

1、PageHelpler使用步骤:

官方地址:https://pagehelper.github.io/

PageHelpler使用步骤:

  第一步:引入jar包
  第二步:配置拦截器插件  <plugins>  -->  <pugin  >  -->  <property>
  			在property标签中定义参数(参数看官网)
  第三步:在代码中使用(官网提供了很多方式)
1、引入jar
        <dependency>
            <groupId>com.github.pagehelper</groupId>
            <artifactId>pagehelper</artifactId>
            <version>4.2.1</version>
        </dependency>
        
2、配置全局文件
 	<plugins>
        <plugin interceptor="com.github.pagehelper.PageInterceptor">
                <!-- 使用下面的方式配置参数,后面会有所有的参数介绍 -->
				<!-- <property name="param1" value="value1"/>-->
         </plugin>
    </plugins>
    
3、使用(官网提供的方式有下面几种)
	//第一种,RowBounds方式的调用
	List<Country> list = sqlSession.selectList("x.y.selectIf", null, new RowBounds(0, 10));
	
	//第二种,Mapper接口方式的调用,推荐这种使用方式。
	PageHelper.startPage(1, 10);
	List<Country> list = countryMapper.selectIf(1);
	
	//第三种,Mapper接口方式的调用,推荐这种使用方式。
	PageHelper.offsetPage(1, 10);
	List<Country> list = countryMapper.selectIf(1);
	
	//第四种,参数方法调用
	//存在以下 Mapper 接口方法,你不需要在 xml 处理后两个参数
	public interface CountryMapper {
	    List<Country> selectByPageNumSize(
	            @Param("user") User user,
	            @Param("pageNum") int pageNum,
	            @Param("pageSize") int pageSize);
	}
	//配置supportMethodsArguments=true
	//在代码中直接调用:
	List<Country> list = countryMapper.selectByPageNumSize(user, 1, 10);
	
	//第五种,参数对象
	//如果 pageNum 和 pageSize 存在于 User 对象中,只要参数有值,也会被分页
	//有如下 User 对象
	public class User {
	    //其他fields
	    //下面两个参数名和 params 配置的名字一致
	    private Integer pageNum;
	    private Integer pageSize;
	}
	//存在以下 Mapper 接口方法,你不需要在 xml 处理后两个参数
	public interface CountryMapper {
	    List<Country> selectByPageNumSize(User user);
	}
	//当 user 中的 pageNum!= null && pageSize!= null 时,会自动分页
	List<Country> list = countryMapper.selectByPageNumSize(user);
	
	//第六种,ISelect 接口方式
	//jdk6,7用法,创建接口
	Page<Country> page = PageHelper.startPage(1, 10).doSelectPage(new ISelect() {
	    @Override
	    public void doSelect() {
	        countryMapper.selectGroupBy();
	    }
	});
	//jdk8 lambda用法
	Page<Country> page = PageHelper.startPage(1, 10).doSelectPage(()-> countryMapper.selectGroupBy());
	
	//也可以直接返回PageInfo,注意doSelectPageInfo方法和doSelectPage
	pageInfo = PageHelper.startPage(1, 10).doSelectPageInfo(new ISelect() {
	    @Override
	    public void doSelect() {
	        countryMapper.selectGroupBy();
	    }
	});
	//对应的lambda用法
	pageInfo = PageHelper.startPage(1, 10).doSelectPageInfo(() -> countryMapper.selectGroupBy());
	
	//count查询,返回一个查询语句的count数
	long total = PageHelper.count(new ISelect() {
	    @Override
	    public void doSelect() {
	        countryMapper.selectLike(country);
	    }
	});
	//lambda
	total = PageHelper.count(()->countryMapper.selectLike(country));

2、案例:

  (1)配置好分页插件之后,在要分页的查询方法之前添加:
  		方法一:
  				//得到每一页的数据
  				PageHelper.startPage(开始位置,个数);
  				查询语句
  		方法二:
  				使用pageInfo类,可以设置连续显示几个PageHelper分好的页
  				把查询来的数据list,使用PageInfo对象包装
  				PageInfo<User> pageInfo = new PageInfo<User>(分好页的数据,连续显示的页数);

  (2)分页插件还可以查看当前分页的详细信息:
  			Page<Object> page = PageHelper.startPage(开始位置,个数);
  			通过page.getXXX  拿到各种信息

  			还可以通过pageInfo拿到各种值	
	//分页插件的使用
	@Test
	public void test3()throws Exception{
		SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream("Config.xm"));
		SqlSession sqlSession = sqlSessionFactory.openSession();
		UserMapper mapper = sqlSession.getMapper(UserMapper.class);

		//在查询方法之前调用下面语句,进行分页
		Page<Object> page = PageHelper.startPage(1, 5);
		//查询方法
		List<User> users = mapper.selectByExample(null);
		//连续显示几页的设置(3页)
		PageInfo<User> pageInfo = new PageInfo<User>(users,3);
		for (User i:users)
			System.out.println(i.toString());

		System.out.println("当前页码:"+page.getPageNum());
		System.out.println("总记录数"+page.getTotal());
		System.out.println("每页的记录数"+page.getPageSize());
		System.out.println("总页码"+page.getPages());

		System.out.println("当前页码:"+pageInfo.getPageNum());
		System.out.println("总记录数"+pageInfo.getTotal());
		System.out.println("每页的记录数"+pageInfo.getPageSize());
		System.out.println("总页码"+pageInfo.getPages());
		System.out.println("是否第一页:"+pageInfo.isIsFirstPage());
		System.out.println("连续显示的页码");
		int[] nums = pageInfo.getNavigatepageNums();
		for (int i:nums)
			System.out.println(i);

	}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小镇男孩~~

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值