- PageHelper插件进行分页
- 批量操作
- 存储过程
- typeHandler处理枚举
PageHelper插件进行分页
- PageHelper是MyBatis中非常方便的第三方分页插件
- 官方文档:https://github.com/pagehelper/Mybatis-PageHelper/blob/master/wikis/zh/HowToUse.md
- 我们可以对照官方文档的说明,快速的使用插件
使用步骤
导入相关包
pagehelper-x.x.x.jar
和jsqlparser-0.9.5.jar
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper</artifactId>
<version>最新版本</version>
</dependency>
在MyBatis全局配置文件中配置分页插件。
<plugins> <!--com.github.pagehelper.PageInterceptor--> <plugin interceptor="com.github.pagehelper.PageInterceptor"> <!--使用下面的方式配置参数,后面会有所有参数介绍--> <property name="param1" value="value1"/> </plugin> </plugins>
使用PageHelper提供的方法进行分页
- 可以使用更强大的PageInfo封装返回结果
批量操作
- 默认的openSession()方法没有参数,他会创建有如下特征的
- 会开启一个事务(也就是不自动提交)
- 连接对象会从由活动环境配置的数据源实例得到。
- 事务隔离级别将会使用驱动或数据源的默认设置
- 预处理语句不会被复用,也不会批量处理更新。
- openSession方法的ExecutorType类型的参数,枚举类型:
- ExecutorType.SIMPLE:这个执行器类型不做特殊处理的事情(这是默认装配的)。它为每个语句的执行创建了一个新的预处理语句。
- ExecutorType.REUSE:这个执行器类型会复用预处理语句。
- ExecutorType.BATCH:这个执行器会批量执行所有更新语句。 ``` SqlSession openSession(boolean autoCommit); SqlSession openSession(Connection connection); SqlSession openSession(TransactionIsolationLevel level);
SqlSession openSession(Executor execType); SqlSession openSession(Executor execType, boolean autoCommit); SqlSession openSession(Executor execType, TransactionIsolationLevel level); SqlSession openSession(Executor execType, Connection connection);
4. 批量操作我们是使用MyBatis提供的BatchExecutor进行的,他的底层就是通过jdbc攒sql的方式进行的。我们可以让他攒够一定数量后发送给数据库一次。
```java
public void test01() {
SqlSession openSession = build.openSession(ExecutorType.BATCH);
UserDao mapper = openSession.getMapper(UserDao.class);
long start = System.currentTimeMillis();
for (int i = 0; i < 1000000; i++) {
String name = UUID.randomUUID().toString().substring(0, 5);
mapper.addUser(new User(null, name, 13));
}
openSession.commit();
openSession.close();
long end = System.currentTimeMillis();
System.out.println("耗时时间:"+(end-start));
}
// 100w记录添加测试结果:耗时:75567
与Spring整合中,我们推荐,额外的配置一个可以专门用来执行批量操作的sqlSession
<bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate"> <constructor-arg name="sqlSessionFactory" ref="sqlSessionFactoryBean"></constructor-arg> <constructor-arg name="executor" value="BATCH"></constructor-arg> </bean>
需要用到批量操作的时候,我们可以注入配置的这个批量SqlSession。通过他获取到mapper映射器进行操作。 ```java @Service public class EmployeeService {
@Autowired private EmployeeMapper employeeMapper;
@Autowired private SqlSession sqlSession;
public List
getEmp() { EmployeeMapper mapper = sqlSession.getMapper(EmployeeMapper.class); return mapper.getEmp();
}
}
10. <br />
<a name="138a6766"></a>
## 注意
1. 批量操作是在session.commit() 以后才发送sql语句给数据库进行执行的。
1. 如果我们想让其提前执行,以方便后续可能的查询操作获取数据,我们可以使用sqlSession.flushStatements() 方法,让其直接冲刷到数据库进行执行。
<a name="a74b3354"></a>
# 存储过程
1. 在实际开发中,我们通常也会写一写存储过程,MyBatis也支持对存储过程的调用。
1. 一个最简单的存储过程
```shell
delimiter $$
create procedure test()
begin
select 'hello';
end $$
delimiter;
- 存储过程的调用
- select标签中statementType=”CALLABLE”
- 标签体中调用方法:
{call procedure_name(#{param1_info}, #{param2_info})}
存储过程-游标处理
- MyBatis对存储过程的游标提供了一个JdbcType=CURSOR的支持,可以智能的把游标读取到的数据,映射到我们声明的结果集中
- 调用实例:
// xml配置文件
<select id="getPage" paramterType="PageEmp" statementType="CALLABLE" databaseId="oracle">
{call PAGE_EMP(
#{start, mode=IN, jdbcType=INTEGER},
#{end, mode=IN, jdbcType=INTEGER},
#{count, mode=OUT, jdbcType=INTEGER},
#{emps, mode=OUT, jdbcType=CURSOR, javaType=ResultSet, resultMap=TestEmp}
)}
</select>
<resultMap type="Emp" id="TestEmp">
<id column="EMPNO" property="id"/>
</resultMap>
# properties文件
orcl.driver=oracle.jdbc.OracleDriver
orcl.url=jdbc:oracle:thin:@localhost:1521:orcl
orcl.username=scott
orcl.password=123456
// bean对象
public class PageEmp {
private int start;
private int end;
private int count;
private List<Emp> emps;
}
<!--mybatis-config.xml-->
<environment id="oracle_dev">
<transactionManager type="JDBC" />
<dataSource type="POOLED">
<property name="driver" value="${orcl.driver}" />
<property name="url" value="${orcl.url}" />
<property name="username" value="${orcl.username}" />
<property name="password" value="${orcl.password}" />
</dataSource>
</environment>
<databaseIdProvider type="DB_VENDOR">
<property name="MySQL" value="mysql"/>
<property name="Oracle" value="oracle"/>
</databaseIdProvider>
create or replace procedure
hello_test(p_start in int,
p_end in int,
p_count out int,
ref_cur out sys_refcursor) AS
BEGIN
select count(*) into p_count from emp;
open ref_cur for
select * from (select e.* rownum as r1 from emp e where rownum < p_end)
where r1 > p_start;
END hello_test;
自定义TypeHandler处理枚举
- 我们可以通过自定义TypeHandler的形式来在设置参数或者取出结果集的时候自定义参数封装策略。
- 步骤:
- 实现TypeHandler接口或者继承BaseTypeHandler
- 使用@MappedTypes 定义处理的java类型;使用@MappedJdbcTypes 定义jdbcType类型
- 在自定义结果集标签或者参数处理的时候声明使用自定义TypeHandler进行处理,或者在全局TypeHandler要处理的javaType
测试实例
一个代表部门状态的枚举类
public enum DeptStatus {
WORKING(100, "部门正在开会中");
MEETING(200, "部门正在工作中");
VOCATION(300, "部门正在休假中");
}
测试全局配置EnumOrdinalTypeHandler
<typeHandlers> <typeHandler handler="org.apache.ibatis.type.EnumOrdinalTypeHanlder" javaType="com.zh.bean.DeptStateus"/> </typeHandlers>
测试全局配置EnumTypeHandler
<typeHandlers> <typeHandler handler="org.apache.ibatis.type.EnumTypeHanlder" javaType="com.zh.bean.DeptStateus"/> </typeHandlers>
测试参数位置设置自定义TypeHandler
<insert id="addDept"> insert into department(dept_name, status) values(#{deptName}, #{status, typeHandler = com.zh.type.MyEnumTypeHandler}) </insert>
自定义TypeHandler
package com.zh.mybatis.typeHandler;
import com.zh.mybatis.bean.EmpStatus;
import org.apache.ibatis.type.JdbcType;
import org.apache.ibatis.type.TypeHandler;
import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
/**
* @author cai-xiansheng
* @Description
* 1. 实现TypeHandler,或者继承BaseTypeHandler
* @create 2020-10-04 13:00
*/
public class MyEnumEmpStatusHandler implements TypeHandler<EmpStatus> {
/**
* 定义参数如何保存进数据库中
* @param ps
* @param i
* @param parameter
* @param jdbcType
* @throws SQLException
*/
@Override
public void setParameter(PreparedStatement ps, int i, EmpStatus parameter, JdbcType jdbcType) throws SQLException {
ps.setString(i, parameter.getCode().toString());
System.out.println("调用MyEnumEmpStatusHandler");
}
@Override
public EmpStatus getResult(ResultSet rs, String columnName) throws SQLException {
// 需要根据从数据库中拿到的枚举的状态码返回一个枚举状态
int code = rs.getInt(columnName);
System.out.println("从数据库中获取的状态码:" + code);
EmpStatus status = EmpStatus.getEmpStatusByCode(code);
return status;
}
@Override
public EmpStatus getResult(ResultSet rs, int columnIndex) throws SQLException {
// 需要根据从数据库中拿到的枚举的状态码返回一个枚举状态
int code = rs.getInt(columnIndex);
System.out.println("从数据库中获取的状态码:" + code);
EmpStatus status = EmpStatus.getEmpStatusByCode(code);
return status;
}
@Override
public EmpStatus getResult(CallableStatement cs, int columnIndex) throws SQLException {
// 需要根据从数据库中拿到的枚举的状态码返回一个枚举状态
int code = cs.getInt(columnIndex);
System.out.println("从数据库中获取的状态码:" + code);
EmpStatus status = EmpStatus.getEmpStatusByCode(code);
return status;
}
}
注册Handler
<!--mybatis-config.xml-->
<!--类型处理器-->
<typeHandlers>
<!--1. 配置我们自定义的类型处理器TypeHandler-->
<typeHandler handler="com.zh.mybatis.typeHandler.MyEnumEmpStatusHandler" javaType="com.zh.mybatis.bean.EmpStatus"/>
<!--
2. 也可以在处理某个字段的时候告诉MyBatis用什么类型处理器
保存:#{empStatus, typeHandler=xxx}
查询:
<resultMap id="MyEmp" type="com.zh.mybatis.bean.Employee">
<id column="id" property="id"/>
<result column="empStatus" property="empStatus" typeHandler="xxx"/>
</resultMap>
注意:如果在参数位置修改TypeHandler,应该保证数据的查询和存储用的同一个typeHandler
-->
</typeHandlers>
枚举类
package com.zh.mybatis.bean;
/**
* @author cai-xiansheng
* @Description 希望数据库保存的是100,200这些状态码,而不是1,0索引
* @create 2020-10-04 12:33
*/
public enum EmpStatus {
LOGIN(100, "用户登录"), LOGOUT(200, "用户登出"), REMOVE(300, "用户不存在");
private Integer code;
private String msg;
private EmpStatus(Integer code, String msg) {
this.code = code;
this.msg = msg;
}
public Integer getCode() {
return code;
}
public String getMsg() {
return msg;
}
public void setCode(Integer code) {
this.code = code;
}
public void setMsg(String msg) {
this.msg = msg;
}
// 按照状态码返回枚举对象
public static EmpStatus getEmpStatusByCode(Integer code) {
switch (code) {
case 100:
return LOGIN;
case 200:
return LOGOUT;
case 300:
return REMOVE;
default:
return LOGOUT;
}
}
}