文章目录
一、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