背景
-
依赖导入
maven依赖
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper</artifactId>
<version>4.2.0</version>
</dependency>
配置
mybatis-config.xml ```java <?xml version=”1.0” encoding=”UTF-8” ?> <!DOCTYPE configuration PUBLIC “-//mybatis.org//DTD Config 3.0//EN” “http://mybatis.org/dtd/mybatis-3-config.dtd">
<settings>
<!-- 开启驼峰命名匹配-->
<setting name="mapUnderscoreToCamelCase" value="true"/>
</settings>
<plugins>
<plugin interceptor="com.github.pagehelper.PageHelper" >
</plugin>
</plugins>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC" />
<dataSource type="POOLED">
<property name="driver" value="${jdbc.driver}" />
<property name="url" value="${jdbc.url}" />
<property name="username" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
</dataSource>
</environment>
</environments>
<!-- 将我们写好的sql映射文件(EmployeeMapper.xml)一定要注册到全局配置文件(mybatis-config.xml)中 -->
<mappers>
<mapper resource="EmployeeMapper.xml" />
</mappers>
- 注意:配置文件有严格的书写顺序,如果报错百度或者看提示修改即可。
<a name="ow1PC"></a>
# 简单使用
```java
@Test
public void testMyBatis3Simple() throws IOException {
SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();
SqlSession openSession = sqlSessionFactory.openSession();
try {
EmployeeMapper mapper = openSession.getMapper(EmployeeMapper.class);
Page<Object> page = PageHelper.startPage(1, 5);
List<Employee> emps = mapper.getEmps();
// PageInfo<Employee> employeePageInfo = new PageInfo<>(emps);
// public PageInfo(List<T> list, int navigatePages) 两参数构造器 设置分页的数据以及连续展示几页
PageInfo<Employee> employeePageInfo = new PageInfo<>(emps, 5);
for (Employee emp : emps) {
System.out.println(emp);
}
System.out.println("当前页码:" + page.getPageNum());
System.out.println(page.getPages());
System.out.println(page.getPageSize());
System.out.println(employeePageInfo.getPageNum());
System.out.println(employeePageInfo.getTotal());
System.out.println(employeePageInfo.getPageSize());
System.out.println(employeePageInfo.getPages());
System.out.println(employeePageInfo.isIsFirstPage());
System.out.println(employeePageInfo.isIsLastPage());
int[] navigatepageNums = employeePageInfo.getNavigatepageNums();
for (int i = 0; i < navigatepageNums.length; i++) {
System.out.println(navigatepageNums[i]);
}
} finally {
openSession.close();
}
}
插件生效原理
mybatis 在执行查询的过程中会创建三大对象,三大对象都会同时调用插件链,然后分别完成不同阶段的插件增强方法执行
/** * 插件原理 * 在四大对象创建的时候 * 1、每个创建出来的对象不是直接返回的,而是 * interceptorChain.pluginAll(parameterHandler); * 2、获取到所有的Interceptor(拦截器)(插件需要实现的接口); * 调用interceptor.plugin(target);返回target包装后的对象 * 3、插件机制,我们可以使用插件为目标对象创建一个代理对象;AOP(面向切面) * 我们的插件可以为四大对象创建出代理对象; * 代理对象就可以拦截到四大对象的每一个执行; * public Object pluginAll(Object target) { for (Interceptor interceptor : interceptors) { target = interceptor.plugin(target); } return target; } */
自定义TypeHandler
理解typeHandler是什么
- 在mybatis中负责完成javabean与jdbc数据数据类型映射的一个对象。
简单来说,在java程序中,字符串定义为String类型,而数据库中则是char,varchar,typehandler就负责将这个过程进行转换。
使用场景
比如我们要将java中的枚举类型放入db中,首先复习一下枚举类 ```java — 简单定义 public enum StatusEnum { LOGIN,FAIL,LOGOUT;
} — 但是实际应用场景一般都是比这更加复杂且封装更多
/**
- 希望数据库保存的是100,200这些状态码,而不是默认0,1或者枚举的名
- @author lfy / public enum EmpStatus { // 定义枚举对象,由 integer String组成 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 void setCode(Integer code) {
this.code = code;
}
public String getMsg() {
return msg;
}
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;
}
}
}
<a name="Cl3ze"></a>
# 自定义TypeHandler来完成存放状态码到db中
```java
package com.atguigu.mybatis.typehandler;
import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import org.apache.ibatis.type.JdbcType;
import org.apache.ibatis.type.TypeHandler;
import com.atguigu.mybatis.bean.EmpStatus;
/**
* 1、实现TypeHandler接口。或者继承BaseTypeHandler
* @author lfy
*
*/
public class MyEnumEmpStatusTypeHandler implements TypeHandler<EmpStatus> {
/**
* 定义当前数据如何保存到数据库中
*/
@Override
public void setParameter(PreparedStatement ps, int i, EmpStatus parameter,
JdbcType jdbcType) throws SQLException {
// TODO Auto-generated method stub
System.out.println("要保存的状态码:"+parameter.getCode());
ps.setString(i, parameter.getCode().toString());
}
@Override
public EmpStatus getResult(ResultSet rs, String columnName)
throws SQLException {
// TODO Auto-generated method stub
//需要根据从数据库中拿到的枚举的状态码返回一个枚举对象
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 {
// TODO Auto-generated method stub
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 {
// TODO Auto-generated method stub
int code = cs.getInt(columnIndex);
System.out.println("从数据库中获取的状态码:"+code);
EmpStatus status = EmpStatus.getEmpStatusByCode(code);
return status;
}
}
mybatis中进行配置
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<properties resource="dbconfig.properties"></properties>
<typeHandlers>
<!--1、配置我们自定义的TypeHandler -->
<typeHandler handler="com.atguigu.mybatis.typehandler.MyEnumEmpStatusTypeHandler" javaType="com.atguigu.mybatis.bean.EmpStatus"/>
<!--2、也可以在处理某个字段的时候告诉MyBatis用什么类型处理器
保存:#{empStatus,typeHandler=xxxx}
查询:
<resultMap type="com.atguigu.mybatis.bean.Employee" id="MyEmp">
<id column="id" property="id"/>
<result column="empStatus" property="empStatus" typeHandler=""/>
</resultMap>
注意:如果在参数位置修改TypeHandler,应该保证保存数据和查询数据用的TypeHandler是一样的。
-->
</typeHandlers>
<plugins>
<plugin interceptor="com.github.pagehelper.PageInterceptor"></plugin>
</plugins>
<environments default="dev_mysql">
<environment id="dev_mysql">
<transactionManager type="JDBC" />
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://localhost:3306/mybatis" />
<property name="username" value="root" />
<property name="password" value="123456" />
</dataSource>
</environment>
<environment id="dev_oracle">
<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>
</environments>
<databaseIdProvider type="DB_VENDOR">
<property name="MySQL" value="mysql"/>
<property name="Oracle" value="oracle"/>
<property name="SQL Server" value="sqlserver"/>
</databaseIdProvider>
<!-- 将我们写好的sql映射文件(EmployeeMapper.xml)一定要注册到全局配置文件(mybatis-config.xml)中 -->
<mappers>
<mapper resource="EmployeeMapper.xml" />
</mappers>
</configuration>
测试类
st
public void testEnumUse(){
EmpStatus login = EmpStatus.LOGIN;
System.out.println("枚举的索引:"+login.ordinal());
System.out.println("枚举的名字:"+login.name());
System.out.println("枚举的状态码:"+login.getCode());
System.out.println("枚举的提示消息:"+login.getMsg());
}
/**
* 默认mybatis在处理枚举对象的时候保存的是枚举的名字:EnumTypeHandler
* 改变使用:EnumOrdinalTypeHandler:
* @throws IOException
*/
@Test
public void testEnum() throws IOException{
SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();
SqlSession openSession = sqlSessionFactory.openSession();
try{
EmployeeMapper mapper = openSession.getMapper(EmployeeMapper.class);
Employee employee = new Employee("test_enum", "enum@atguigu.com","1");
//mapper.addEmp(employee);
//System.out.println("保存成功"+employee.getId());
//openSession.commit();
Employee empById = mapper.getEmpById(30026);
System.out.println(empById.getEmpStatus());
}finally{
openSession.close();
}
}
批量操作
当需要批量插入数量级很大的sql记录的时候,最好使用批量操作 ```java @Test public void testBatch() throws IOException{
SqlSessionFactory sqlSessionFactory = getSqlSessionFactory(); //可以执行批量操作的sqlSession SqlSession openSession = sqlSessionFactory.openSession(ExecutorType.BATCH); long start = System.currentTimeMillis(); try{ EmployeeMapper mapper = openSession.getMapper(EmployeeMapper.class); for (int i = 0; i < 10000; i++) { mapper.addEmp(new Employee(UUID.randomUUID().toString().substring(0, 5), "b", "1")); } openSession.commit(); long end = System.currentTimeMillis(); //批量:(预编译sql一次==>设置参数===>10000次===>执行(1次)) //Parameters: 616c1(String), b(String), 1(String)==>4598 //非批量:(预编译sql=设置参数=执行)==》10000 10200 System.out.println("执行时长:"+(end-start)); }finally{ openSession.close(); }
}
批量非批量之间的区别
- 批量
- 预编译sql一次->设置参数->10000次->执行 只1次
- 非批量
- 预编译sql->设置参数->执行, 重复10000次,效率大打折扣。