MyBatis应用拓展(五)

一、Mybatis之PageHelper分页插件

1.1、PageHelper插件意义

  在涉及到分页查询的时候,无论是mysql或Oracle,使用SQL写分页都比较麻烦和复杂,且灵活性差。所以就有了PageHelper分页插件的存在。

PageHelper插件进行分页
•PageHelper是MyBatis中非常方便的第三方分页插件。
官方文档:
https://github.com/pagehelper/Mybatis
PageHelper/blob/master/README_zh.md

1.2、PageHelper插件使用

使用步骤
1、新建一个Maven项目,并且引入MyBatis相关jar包和配置文件:
忘记的童鞋参考Mabatis第一章MyBatis深入浅出知识。
在这里插入图片描述

2、导入PageHelper插件jar包

<dependency>
    <groupId>com.github.pagehelper</groupId>
    <artifactId>pagehelper</artifactId>
    <version>5.1.10</version>
</dependency>

由于使用了SQL解析工具,所以还需要下载jsqlparser的jar包:

<dependency>
    <groupId>com.github.jsqlparser</groupId>
    <artifactId>jsqlparser</artifactId>
    <version>3.1</version>
</dependency>

3、在Dao接口中新增一个查询方法:
在这里插入图片描述
4、Mapper文件里面写一个映射SQL:

<select id="getEmpsWithPage" resultType="com.xiaolang.mybatis.bean.Employee">
    select * from emp
</select>

5、在MyBatis全局配置文件中引入PageHelper插件
在配置文件中添加,拦截器插件(复制官网),注意顺序

<!--
    plugins在配置文件中的位置必须符合要求,否则会报错,顺序如下:
    properties?, settings?,
    typeAliases?, typeHandlers?,
    objectFactory?,objectWrapperFactory?,
    plugins?,
    environments?, databaseIdProvider?, mappers?
-->

在这里插入图片描述
如果是mybatis整合了Spring,可以在Spting的配置文件中配置拦截器插件,使用spring的属性配置方式,在这里不细说。

5、案例一测试:

public class EmpTest {

    public SqlSessionFactory getSqlSessionFactory() throws IOException {
        String resource = "SqlMapConfig.xml";
        InputStream inputStream = Resources.getResourceAsStream(resource);
        return new SqlSessionFactoryBuilder().build(inputStream);
    }

    @Test
    public void queryEmpsWithPage() throws IOException {
        SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();
        SqlSession openSession = sqlSessionFactory.openSession();
        EmployeeMapper mapper = openSession.getMapper(EmployeeMapper.class);

        Page<Object> page = PageHelper.startPage(1, 5);//第一页数据,每页显示5条记录

        List<Employee> empList = mapper.getEmpsWithPage();
        for (Employee emp : empList) {
            System.out.println(emp.toString());
        }
        System.out.println("当前页面:"+page.getPageNum());
        System.out.println("总记录数:"+page.getTotal());
        System.out.println("每页多少条记录:"+page.getPageSize());
        System.out.println("总页数:"+page.getPages());
    }
}

结果:
在这里插入图片描述

案例测试二:使用pageInfo的用法

    @Test
    public void queryEmpsWithPage() throws IOException {
        SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();
        SqlSession openSession = sqlSessionFactory.openSession();
        EmployeeMapper mapper = openSession.getMapper(EmployeeMapper.class);

        Page<Object> page = PageHelper.startPage(1, 5);//第一页数据,每页显示5条记录
        List<Employee> empList = mapper.getEmpsWithPage();

        for (Employee emp : empList) {
            System.out.println(emp.toString());
        }
        
        //把查询的结果封装到Pageinfo中
        PageInfo<Employee> pageinfo=new PageInfo<>(empList);
        System.out.println("上一页:"+pageinfo.getPrePage());
        System.out.println("当前页:"+pageinfo.getPageNum());
        System.out.println("下一页:"+pageinfo.getNextPage());
        System.out.println("总页数:"+pageinfo.getPages());
        System.out.println("每页记录数:"+pageinfo.getTotal());
        System.out.println("总记录数:"+pageinfo.getTotal());
        System.out.println("是否第一页:"+pageinfo.isIsFirstPage());
        System.out.println("是否最后第一页:"+pageinfo.isIsLastPage());
    }
}

案例测试三:使用pageInfo传入分页导航的来连续显示多少页

    @Test
    public void queryEmpsWithPage() throws IOException {
        SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();
        SqlSession openSession = sqlSessionFactory.openSession();
        EmployeeMapper mapper = openSession.getMapper(EmployeeMapper.class);

        Page<Object> page = PageHelper.startPage(1, 5);//第一页数据,每页显示5条记录
        List<Employee> empList = mapper.getEmpsWithPage();

        for (Employee emp : empList) {
            System.out.println(emp.toString());
        }

        //把查询的结果封装到Pageinfo中
        //连续显示5页的数据
        PageInfo<Employee> pageinfo=new PageInfo<>(empList,5);
        System.out.println("上一页:"+pageinfo.getPrePage());
        System.out.println("当前页:"+pageinfo.getPageNum());
        System.out.println("下一页:"+pageinfo.getNextPage());
        System.out.println("总页数:"+pageinfo.getPages());
        System.out.println("每页记录数:"+pageinfo.getTotal());
        System.out.println("总记录数:"+pageinfo.getTotal());
        System.out.println("是否第一页:"+pageinfo.isIsFirstPage());
        System.out.println("是否最后第一页:"+pageinfo.isIsLastPage());

        int[] navigatepageNums = pageinfo.getNavigatepageNums();
        for (int i : navigatepageNums) {
            System.out.print("连续显示的页码:"+i+"\t");
        }
    }

二、Mybatis之批量操作

2.1、defaultExecutorType执行器标签

之前我们采用forearch的动态语法来实现了MyBatis批量插入,修改等操作。严格来说,是不算批量操作的,因为其做法就是将批量的数据拼装成一个很长的SQL,然后让数据库来执行。而数据库服务器是不能接收太长的SQL语句的。Myatis在执行批量操作的时候提供了一个批量执行器

在MyBatis全局配置文件中的<Settings>标签中有一个defaultExecutorType,其属性默认用的是SIMPLE,SIMPLE就是会创建一个Executor执行器,来执行简单增、删、改、查方法。而有一个属性是BATCH批量执行器,能执行批量SQL。如果我们在全局配置文件中一修改,那么所有的SQL都会执行批量,所以我们不能直接在批量文件中添加

2.2、defaultExecutorType执行器使用

1、增加批量插入Dao接口:
在这里插入图片描述
2、在Mapper中写映射SQL:

  <insert id="addEmps">
    insert into emp(last_name, gender, phone)
    values (#{last_name}, #{gender}, #{phone})
  </insert>

3、使用一般方式执行批量插入:


    @Test
    public void addEmps() throws IOException {
        SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();

        //获取一个批量操作的sqlSession对象
        SqlSession openSession = sqlSessionFactory.openSession();
        EmployeeMapper mapper = openSession.getMapper(EmployeeMapper.class);

        long startTime = System.currentTimeMillis();
        System.out.println("开始时间:"+System.currentTimeMillis());
        for (int i=0; i<10000; i++){
            mapper.addEmps(new Employee(null,"李欣"+i,"女", "1379080934",null));
        }

        long endTime = System.currentTimeMillis();
        System.out.println("结束时间:"+endTime);
        long time = endTime - startTime;
        System.out.println("耗时:"+time);

        openSession.close();
    }

结果:发现每一个插入SQL都是先编译,插入参数,执行三个步骤
在这里插入图片描述

4、编写测试代码,使用批量操作的sqlSession执行SQL:


    @Test
    public void addEmps() throws IOException {
        SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();

        //获取一个批量操作的sqlSession对象
        SqlSession openSession = sqlSessionFactory.openSession(ExecutorType.BATCH);
        EmployeeMapper mapper = openSession.getMapper(EmployeeMapper.class);

        long startTime = System.currentTimeMillis();
        System.out.println("开始时间:"+System.currentTimeMillis());
        for (int i=0; i<10000; i++){
            mapper.addEmps(new Employee(null,"李欣"+i,"女", "1379080934",null));
        }

        long endTime = System.currentTimeMillis();
        System.out.println("结束时间:"+endTime);
        long time = endTime - startTime;
        System.out.println("耗时:"+time);

        openSession.close();
    }

结果:发现先对SQL进行与预编译,最后才执行SQL
在这里插入图片描述
结果:

一般的方式:每一个插入SQL都是先预编译SQL一次,插入参数再一次,最后交给数据库执行。耗时叫长,资源利用率低
批量操作:先对SQL语句发给数据库进行预编译,然后设置参数,最后一起执行。

2.3、Spring整合批量操作

以上我们说的做法是在MyBatis上完成批量操作的。那么如果当Mabatis和Spring整合的时候,我们可以去spring的配置文件applicationContext.xml中进行配置:
在这里插入图片描述
然后使用自动注册,直接调用sqlSession执行crud即可。

三、Mybatis之存储过程调用

3.1、存储过程调用方法

在这里插入图片描述

3.2、存储过程调步骤

场景:使用Oracle的存储过程实现分页查询

1、新建一个Page对象用于分装分页数据:

package com.xiaolang.mybatis.bean;
import java.util.List;

public class Page {
    private int start;
    private int end;
    private int count;
    private List<Employee> emps;

    public Page() {
    }

    public Page(int start, int end, int count) {
        this.start = start;
        this.end = end;
        this.count = count;
    }

    public int getStart() {
        return start;
    }

    public void setStart(int start) {
        this.start = start;
    }

    public int getEnd() {
        return end;
    }

    public void setEnd(int end) {
        this.end = end;
    }

    public int getCount() {
        return count;
    }

    public void setCount(int count) {
        this.count = count;
    }

    public List<Employee> getEmps() {
        return emps;
    }

    public void setEmps(List<Employee> emps) {
        this.emps = emps;
    }
}

2、写一个Oracle分页的存储过程:

create or procedure `getEmpsWithPro`(p_start in int,
									p_end in int,
									p_count out int,
									p_emps out sys_refcursor
									) as
begin
	select count(*) into p_count from employee;
	open p_emps for 
		select * from (select rownum rn, e.* from employee e where rownum <= p_end)
		where rn >= p_start;
end getEmpsWithPage;  

3、新增一个Dao接口来调用存储过程:
在这里插入图片描述
4、Mapper文件中调用存储过程:

注意:
1、使用select标签调用存储过程
2、将标签属性设置成statementType = “CALLABLE”
3、调用存储错过程格式:{call 存储过程名}

<mapper namespace="com.xiaolang.mybatis.dao.EmployeeMapper">
  <resultMap id="PageEmp" type="com.xiaolang.mybatis.bean.Employee">
    <id column="EMPLOYEE_ID" property="id" />
    <result column="LAST_NAME" property="last_name" />
    <result column="GENDER" property="gender" />
    <result column="PHONE" property="phone" />

  </resultMap>
  <select id="getEmpsByPro" statementType="CALLABLE">
        {call getEmpsWithPro(
                    #{start, mode=IN, jdbcType=INTEGER},
                    #{end, mode=IN, jdbcType=INTEGER},
                    #{count, mode=OUT, jdbcType=INTEGER},
                    #{emps, mode=OUT, jdbcType=CURSOR, javaType=ResultSet, resultMap=PageEmp}
        )}
  </select>
</mapper>

5、测试:

**
 * oracle分页:
 * 		借助rownum:行号;子查询;
 * 存储过程包装分页逻辑
 * @throws IOException 
 */
@Test
public void testProcedure() throws IOException{
	SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();
	SqlSession openSession = sqlSessionFactory.openSession();
	try{
		EmployeeMapper mapper = openSession.getMapper(EmployeeMapper.class);
		Page page = new Page(); //自己定义的pageBean
		page.setStart(1);
		page.setEnd(5);
		mapper.getPageByProcedure(page);
		
		System.out.println("总记录数:"+page.getCount());
		System.out.println("查出的数据:"+page.getEmps().size());
		System.out.println("查出的数据:"+page.getEmps());
	}finally{
		openSession.close();
	}
}

四、自定义TypeHandler处理枚举

在这里插入图片描述
  我们可以通过自定义TypeHandler的形式来在设置参数或者取出结果集的时候自定义参数封装策略。

4.1、自定义TypeHandler类型处理器

–1、实现TypeHandler接口或者继承BaseTypeHandler
–2、使用@MappedTypes定义处理的java类型
使用@MappedJdbcTypes定义jdbcType类型
–3、在自定义结果集标签或者参数处理的时候声明使用自定义TypeHandler进行处理
或者在全局配置TypeHandler要处理的javaType

类型处理器我自觉感觉不是很重要,如果想要学习的同学推荐学习帖子:
https://blog.csdn.net/soonfly/article/details/65628372

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值