2022尚硅谷SSM框架跟学 三 MyBatis基础三
- 9.动态SQL
- 9.1if
- 9.2where
- 方法一:加入恒成立的条件
- 方法二:使用where标签
- 9.3trim
- 9.4choose、when、otherwise
- 9.5foreach
- 9.51批量添加
- 9.52批量删除
- 批量删除方式1
- 批量删除方式2
- 批量删除方式3
- 9.6SQL片段
- 10.MyBatis的缓存
- 10.1MyBatis的一级缓存
- 10.2MyBatis的二级缓存
- 10.3二级缓存的相关配置
- 10.4MyBatis缓存查询的顺序
- 10.5整合第三方缓存EHCache
- 10.5.1添加依赖
- 10.5.2各jar包功能
- 10.5.3创建EHCache的配置文件ehcache.xml
- 10.5.4设置二级缓存的类型
- 10.5.5加入logback日志
- 10.5.6EHCache配置文件说明
- 11.MyBatis的逆向工程
- 11.1创建逆向工程的步骤
- (1)添加依赖和插件
- (2)创建MyBatis的核心配置文件
- (3)创建逆向工程的配置文件
- (4)执行MBG插件的generate目标
- (5)效果
- 11.2QBC查询
- 测试根据主键查询
- 测试无条件查询
- 测试根据条件查询
- 多条件查询
- 多个and查询
- 多个or查询
- 选择性修改
- 普通修改
- 12分页插件
- 12.1分页插件的使用步骤
- (1)添加依赖
- (2)配置分页插件
- 12.2分页插件的使用
9.动态SQL
Mybatis框架的动态SQL技术是一种根据特定条件动态拼装SQL语句的功能,它存在的意义是为了
解决 拼接SQL语句字符串时的痛点问题。
实例:多个查询条件进行查询,设置了条件的话,就一定要出现在sql中,一定要注意默认值的设置和指定。null和" "(空字符串)
新创建一个Module,这里就不再写具体步骤了,可以参考前几章
配置坐标
GroupId:com.atguigu.mybatis
Name:mybatis-dynamicSQL
配置相关文件
注意配置核心配置文件mybatis-config.xml的时候要设置setting
<!-- mapUnderscoreToCamelCase将下划线映射为驼峰 -->
<settings>
<setting name="mapUnderscoreToCamelCase" value="true"/>
<!-- 延迟加载由2个参数决定 lazyLoadingEnabled设置true
aggressiveLazyLoading设置false
-->
<!-- 开启延迟加载(懒加载) -->
<setting name="lazyLoadingEnabled" value="true"/>
<!--aggressiveLazyLoading 设置false按需加载 -->
<!--aggressiveLazyLoading 设置true全部加载 -->
<setting name="aggressiveLazyLoading" value="false"/>
</settings>
配置pojo的实体类Emp
package com.atguigu.mybatis.pojo;
/**
* @ClassName: Emp
* @Description:
* @Author: wty
* @Date: 2023/1/7
*/
public class Emp {
private Integer empId;
private String empName;
private Integer age;
private String gender;
public Emp() {
}
public Emp(Integer empId, String empName, Integer age, String gender) {
this.empId = empId;
this.empName = empName;
this.age = age;
this.gender = gender;
}
public Integer getEmpId() {
return empId;
}
public void setEmpId(Integer empId) {
this.empId = empId;
}
public String getEmpName() {
return empName;
}
public void setEmpName(String empName) {
this.empName = empName;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public String getGender() {
return gender;
}
public void setGender(String gender) {
this.gender = gender;
}
@Override
public String toString() {
return "Emp{" +
"empId=" + empId +
", empName='" + empName + '\'' +
", age=" + age +
", gender='" + gender + '\'' +
'}';
}
}
9.1if
if标签可通过test属性的表达式进行判断,若表达式的结果为true,则标签中的内容会执行;反之标签中的内容不会执行
在DynamicSQLMapper.java中添加方法
/**
* @param
* @return java.util.List<com.atguigu.mybatis.pojo.Emp>
* @description //根据条件查询员工信息
* @param: emp
* @date 2023/1/7 12:03
* @author wty
**/
List<Emp> getEmpByCondition(Emp emp);
在DynamicSQLMapper.xml中添加sql
<!-- List<Emp> getEmpByCondition(Emp emp); -->
<select id="getEmpByCondition" resultType="Emp">
select *
from t_emp
where
<!-- test表示当前标签中实体类的属性是否有效,如果有效,就拼接到sql中,无效就不拼接 -->
<if test="empName != null and empName != '' ">
emp_name = #{empName}
</if>
<if test="age != null and age != ''">
and age = #{age}
</if>
<if test="gender != null and gender != ''">
and gender = #{gender}
</if>
</select>
创建测试类com.atguigu.mybatis.test.DynamicMapperTest,增加方法
@Test
public void getEmpByConditionTest() {
SqlSession sqlSession = SqlSessionUtil.getSqlSession();
DynamicSQLMapper mapper = sqlSession.getMapper(DynamicSQLMapper.class);
Emp emp = new Emp(1, "张三", 20, "男");
List<Emp> list = mapper.getEmpByCondition(emp);
list.forEach(System.out::println);
sqlSession.close();
}
查询结果
9.2where
这里如果把where后面的条件empName置为空,那么再用测试类查询,就是错误的。
同理,如果我们继续蹬鼻子上脸,把后面age和gender都置为空,那么就剩下一个select * from t_emp where的空壳
如何解决这些问题呢,我们来看下,有如下方法
方法一:加入恒成立的条件
在DynamicSQLMapper.xml中加入恒成立的条件
<!-- List<Emp> getEmpByCondition(Emp emp); -->
<select id="getEmpByCondition" resultType="Emp">
select *
from t_emp
where 1 = 1
<!-- test表示当前标签中实体类的属性是否有效,如果有效,就拼接到sql中,无效就不拼接 -->
<if test="empName != null and empName != '' ">
and emp_name = #{empName}
</if>
<if test="age != null and age != ''">
and age = #{age}
</if>
<if test="gender != null and gender != ''">
and gender = #{gender}
</if>
</select>
继续查询上面那个都是空字段的情况,看结果不报错,查询正确
方法二:使用where标签
修改DynamicSQLMapper.xml中的sql子句变为
<!-- 动态sql拼接 方法二:用where标签 -->
<!-- List<Emp> getEmpByCondition(Emp emp); -->
<select id="getEmpByCondition" resultType="Emp">
select *
from t_emp
<where>
<!-- test表示当前标签中实体类的属性是否有效,如果有效,就拼接到sql中,无效就不拼接 -->
<if test="empName != null and empName != '' ">
emp_name = #{empName}
</if>
<if test="age != null and age != ''">
and age = #{age}
</if>
<if test="gender != null and gender != ''">
and gender = #{gender}
</if>
</where>
</select>
直接用测试类查询
验证了结论:
若where标签中的if条件都不满足,则where标签没有任何功能,即不会添加where关键字。
那我们修改一下测试类DynamicMapperTest.java的条件
@Test
public void getEmpByConditionTest() {
SqlSession sqlSession = SqlSessionUtil.getSqlSession();
DynamicSQLMapper mapper = sqlSession.getMapper(DynamicSQLMapper.class);
Emp emp = new Emp(1, "", 20, "");
List<Emp> list = mapper.getEmpByCondition(emp);
list.forEach(System.out::println);
sqlSession.close();
}
查询结果:
验证了结论:
若where标签中的if条件满足,则where标签会自动添加where关键字,并将条件最前方多余的and去掉。
where和if一般结合使用:
a>若where标签中的if条件都不满足,则where标签没有任何功能,即不会添加where关键字
b>若where标签中的if条件满足,则where标签会自动添加where关键字,并将条件最前方多余的and去掉
注意:where标签不能去掉条件最后多余的and
举个例子:如果and放在条件后还可以吗
<!-- trim标签 -->
<!-- List<Emp> getEmpByCondition(Emp emp); -->
<select id="getEmpByCondition" resultType="Emp">
select *
from t_emp
<where>
<!-- test表示当前标签中实体类的属性是否有效,如果有效,就拼接到sql中,无效就不拼接 -->
<if test="empName != null and empName != '' ">
emp_name = #{empName}
</if>
<if test="age != null and age != ''">
age = #{age} and
</if>
<if test="gender != null and gender != ''">
and gender = #{gender}
</if>
</where>
</select>
更改一下测试类查看结果
@Test
public void getEmpByConditionTest() {
SqlSession sqlSession = SqlSessionUtil.getSqlSession();
DynamicSQLMapper mapper = sqlSession.getMapper(DynamicSQLMapper.class);
Emp emp = new Emp(1, "张三", 20, "");
List<Emp> list = mapper.getEmpByCondition(emp);
list.forEach(System.out::println);
sqlSession.close();
}
查看结果:发现报错
这种情况我们就可以用以下的trim标签来解决
9.3trim
trim用于去掉或添加标签中的内容
常用属性:
prefix:在trim标签中的内容的前面添加某些内容
prefixOverrides:在trim标签中的内容的前面去掉某些内容
suffix:在trim标签中的内容的后面添加某些内容
suffixOverrides:在trim标签中的内容的后面去掉某些内容
修改DynamicSQLMapper.xml
<!-- trim标签 -->
<!-- List<Emp> getEmpByCondition(Emp emp); -->
<select id="getEmpByCondition" resultType="Emp">
select *
from t_emp
<!-- trim的标签有4个
prefix prefixOverrides suffix suffixOverrides
prefix在内容前面加上指定内容
prefixOverrides在内容前面去掉指定内容
suffix在内容后面加上指定内容
suffixOverrides在内容后面去掉指定内容
-->
<trim prefix="where" suffixOverrides="and">
<!-- test表示当前标签中实体类的属性是否有效,如果有效,就拼接到sql中,无效就不拼接 -->
<if test="empName != null and empName != '' ">
emp_name = #{empName} and
</if>
<if test="age != null and age != ''">
age = #{age} and
</if>
<if test="gender != null and gender != ''">
and gender = #{gender}
</if>
</trim>
</select>
运行测试类查看结果
并且测试一下,条件为空,也可以自动去掉where
测试一下,where条件为空,只填充and
9.4choose、when、otherwise
choose、when、 otherwise相当于if…、else if…、else
在DynamicSQLMapper.java中添加方法
/**
* @param
* @return java.util.List<com.atguigu.mybatis.pojo.Emp>
* @description //使用choose查询员工信息
* @param: emp
* @date 2023/1/7 13:43
* @author wty
**/
List<Emp> getEmpByChoose(Emp emp);
修改DynamicSQLMapper.xml
<!-- choose、when、 otherwise相当于if... 、else if.. 、else -->
<!-- List<Emp> getEmpByChoose(Emp emp); -->
<select id="getEmpByChoose" resultType="Emp">
select *
from t_emp
<where>
<choose>
<!-- test表示当前标签中实体类的属性是否有效,如果有效,就拼接到sql中,无效就不拼接 -->
<when test="empName != null and empName != ''">
emp_name = #{empName}
</when>
<when test="age != null and age != ''">
age = #{age}
</when>
<when test="gender != null and gender != ''">
gender = #{gender}
</when>
<otherwise>
1 = 1
</otherwise>
</choose>
</where>
</select>
在测试类DynamicMapperTest.java中添加方法
@Test
public void getEmpByChooseTest() {
SqlSession sqlSession = SqlSessionUtil.getSqlSession();
DynamicSQLMapper mapper = sqlSession.getMapper(DynamicSQLMapper.class);
Emp emp = new Emp(1, "", null, "");
List<Emp> list = mapper.getEmpByChoose(emp);
list.forEach(System.out::println);
sqlSession.close();
}
查看结果
要注意,choose,when,otherwise都是选择条件,三个条件一起用,只是会选择第一个进行,剩下的条件就不会跑了,所以不用写and条件。例如:
可以看出多个选择条件都可以成立,但是第一个执行后,就不会再跑其它的了。
9.5foreach
比较重要的标签,用于批量添加和批量删除。
9.51批量添加
在DynamicSQLMapper.java中添加方法
/**
* @param
* @return int
* @description //员工的批量添加
* @param: emps
* @date 2023/1/7 14:03
* @author wty
**/
int insertMoreEmp(@Param("emps") List<Emp> emp);
修改DynamicSQLMapper.xml
<!-- int insertMoreEmp(@Param("emps") List<Emp> emp); -->
<insert id="insertMoreEmp" useGeneratedKeys="true" keyProperty="empId">
insert into t_emp
values
<!--foreach标签
collection属性:放入Mapper接口Param注解中定义的变量即可
item 可以理解为一行数据,即一个对象
separator 表示分隔符,每一次循环后以,分割,最后一次没有
-->
<foreach collection="emps" item="emp" separator=",">
<!-- 这里用emp.empName是因为返回值类型是List,而emp才是每一行数据的实体对象 -->
(null, #{emp.empName}, #{emp.age}, #{emp.gender}, null)
</foreach>
</insert>
在测试类DynamicMapperTest.java中添加方法
@Test
public void insertMoreEmpTest() {
SqlSession sqlSession = SqlSessionUtil.getSqlSession();
DynamicSQLMapper mapper = sqlSession.getMapper(DynamicSQLMapper.class);
List<Emp> list = new ArrayList<>();
list.add(new Emp(null, "周七", 29, "男"));
list.add(new Emp(null, "朱八", 22, "男"));
list.add(new Emp(null, "李九", 23, "女"));
int i = mapper.insertMoreEmp(list);
System.out.println("插入:" + i + "条数据");
sqlSession.close();
}
插入结果
9.52批量删除
批量删除方式1
在DynamicSQLMapper.java中添加方法
/**
* @param
* @return int
* @description //批量删除
* @param: empIds
* @date 2023/1/7 14:39
* @author wty
**/
int deleteMoreEmp(@Param("empIds") Integer[] empIds);
修改DynamicSQLMapper.xml
<!-- int deleteMoreEmp(@Param("empIds") Integer empIds); -->
<delete id="deleteMoreEmp">
delete
from t_emp
where emp_id in
(
<foreach collection="empIds" item="empId" separator=",">
#{empId}
</foreach>
)
</delete>
在测试类DynamicMapperTest.java中添加方法
@Test
public void deleteMoreEmp() {
SqlSession sqlSession = SqlSessionUtil.getSqlSession();
DynamicSQLMapper mapper = sqlSession.getMapper(DynamicSQLMapper.class);
Integer empIds[] = {5, 6, 7};
int i = mapper.deleteMoreEmp(empIds);
System.out.println("删除:" + i + "条数据");
sqlSession.close();
}
查看删除结果:
看到3条已经删除了
批量删除方式2
用另一种批量删除的方式,更改DynamicSQLMapper.xml
<!-- int deleteMoreEmp(@Param("empIds") Integer empIds); -->
<delete id="deleteMoreEmp">
delete
from t_emp
where emp_id in
<!-- open以什么开始 close以什么结束 -->
<foreach collection="empIds" item="empId" separator="," open="(" close=")">
#{empId}
</foreach>
</delete>
先重新执行一下批量插入的方法。
再删除一下,看一下这种方式是否能删除成功。
删除结果
批量删除方式3
修改DynamicSQLMapper.xml
<!-- int deleteMoreEmp(@Param("empIds") Integer empIds); -->
<delete id="deleteMoreEmp">
delete
from t_emp
where
<foreach collection="empIds" item="empId" separator="or">
emp_id = #{empId}
</foreach>
</delete>
执行测试类删除方法前,也先执行一下批量插入的方法
执行测试类DynamicMapperTest.java
@Test
public void deleteMoreEmp() {
SqlSession sqlSession = SqlSessionUtil.getSqlSession();
DynamicSQLMapper mapper = sqlSession.getMapper(DynamicSQLMapper.class);
Integer empIds[] = {11, 12, 13};
int i = mapper.deleteMoreEmp(empIds);
System.out.println("删除:" + i + "条数据");
sqlSession.close();
}
执行结果
总结
foreach标签的属性
collection:设置要循环的数组或者集合
item:用一个字符串表示数组或者集合中的每一个数据
separator:设置每次循环的数据之间的分隔符
open:循环的所有内容以什么开始
close:循环的所有内容以什么结束
9.6SQL片段
sql片段,可以记录一段公共sql片段,在使用的地方通过include标签进行引入
在DynamicSQLMapper.java中添加方法
/**
* @param
* @return java.util.List<com.atguigu.mybatis.pojo.Emp>
* @description //查询所有用户
* @date 2023/1/7 15:10
* @author wty
**/
List<Emp> getAllEmp();
修改DynamicSQLMapper.xml
<sql id="empColumns">
emp_id,emp_name,age,gender,dept_id
</sql>
<!-- List<Emp> getAllEmp(); -->
<select id="getAllEmp" resultType="Emp">
select
<!-- 使用的时候用 include refid属性放sql中的id -->
<include refid="empColumns"></include>
from t_emp
</select>
在测试类DynamicMapperTest.java中添加方法
@Test
public void getAllEmpTest() {
SqlSession sqlSession = SqlSessionUtil.getSqlSession();
DynamicSQLMapper mapper = sqlSession.getMapper(DynamicSQLMapper.class);
List<Emp> list = mapper.getAllEmp();
list.forEach(System.out::println);
sqlSession.close();
}
查询结果
可以看到sql中的字段会在查询的时候调用
10.MyBatis的缓存
10.1MyBatis的一级缓存
MyBatis的一级缓存是默认开启的,创建一个工程就可以直接使用。
创建新的Module
GroupId:com.atguigu.mybatis
Name:mybatis-cache
配置相关信息和参数见前面几章,这里就不赘述了,创建完后工程是这样的:
在CacheMapper.java中添加方法
/**
* @param
* @return com.atguigu.mybatis.pojo.Emp
* @description //根据员工Id查询员工信息
* @param: empId
* @date 2023/1/7 16:44
* @author wty
**/
Emp getEmpById(@Param("empId") Integer empId);
在CacheMapper.xml中新加语句
<sql id="empColumns">
emp_id
,emp_name,age,gender,dept_id
</sql>
<!-- Emp getEmpById(@Param("empId") Integer empId); -->
<select id="getEmpById" resultType="Emp">
select
<include refid="empColumns"></include>
from t_emp
where emp_id = #{empId}
</select>
在测试类CacheMapperTest.java中添加方法测试
@Test
public void getEmpByIdTest() {
SqlSession sqlSession = SqlSessionUtil.getSqlSession();
CacheMapper mapper = sqlSession.getMapper(CacheMapper.class);
Emp emp1 = mapper.getEmpById(4);
System.out.println(emp1);
Emp emp2 = mapper.getEmpById(4);
System.out.println(emp2);
sqlSession.close();
}
查询结果如下:
一级缓存是SqlSession级别的,通过同一个SqlSession查询的数据会被缓存,下次查询相同的数据,就会从缓存中直接获取,不会从数据库重新访问。
既然一级缓存是SqlSession级别的,那我们来看看是不是这样的。
修改CacheMapperTest.java
@Test
public void getEmpByIdTest() {
SqlSession sqlSession1 = SqlSessionUtil.getSqlSession();
CacheMapper mapper1 = sqlSession1.getMapper(CacheMapper.class);
Emp emp1 = mapper1.getEmpById(4);
System.out.println(emp1);
Emp emp2 = mapper1.getEmpById(4);
System.out.println(emp2);
sqlSession1.close();
SqlSession sqlSession2 = SqlSessionUtil.getSqlSession();
CacheMapper mapper2 = sqlSession2.getMapper(CacheMapper.class);
Emp emp3 = mapper2.getEmpById(4);
System.out.println(emp3);
sqlSession2.close();
}
查看结果
可以看到同一个Sqlsession的确再查询第二次时,会使用缓存,而不同的SqlSession查询相同sql的时候,会重新查询,这样就验证了一级缓存是SqlSession级别的。
使一级缓存失效的四种情况:
- 不同的SqlSession对应不同的一级缓存。
- 同一个SqlSession但是查询条件不同。
- 同一个SqlSession两次查询期间执行了任何一次增删改操作。
- 同一个SqlSession两次查询期间手动清空了缓存。
针对情况(3)举个例子来理解
在CacheMapper.java中添加方法
/**
* @param
* @return int
* @description //添加员工信息
* @param: emp
* @date 2023/1/7 17:08
* @author wty
**/
int insertEmp(Emp emp);
在CacheMapper.xml中新加语句
<!-- int insertEmp(Emp emp); -->
<insert id="insertEmp">
insert into t_emp
values (null, #{empName}, #{age}, #{gender}, null)
</insert>
在测试类CacheMapperTest.java中修改getEmpByIdTest方法测试
@Test
public void getEmpByIdTest() {
SqlSession sqlSession1 = SqlSessionUtil.getSqlSession();
CacheMapper mapper1 = sqlSession1.getMapper(CacheMapper.class);
Emp emp1 = mapper1.getEmpById(4);
System.out.println(emp1);
// 如果执行了任意的增删改,则会清空缓存,重新查询
Emp emp = new Emp(null, "周七", 29, "男");
int i = mapper1.insertEmp(emp);
System.out.println("插入了" + i + "条");
Emp emp2 = mapper1.getEmpById(4);
System.out.println(emp2);
sqlSession1.close();
}
在2个查询之间进行一次新增操作
查询结果
结果发现增删改之后,缓存清空,会查询数据库。
针对情况(3)举个例子来理解
修改CacheMapperTest.java中的getEmpByIdTest方法
sqlSession1.clearCache(); // 清理缓存
@Test
public void getEmpByIdTest() {
SqlSession sqlSession1 = SqlSessionUtil.getSqlSession();
CacheMapper mapper1 = sqlSession1.getMapper(CacheMapper.class);
Emp emp1 = mapper1.getEmpById(4);
System.out.println(emp1);
sqlSession1.clearCache();
Emp emp2 = mapper1.getEmpById(4);
System.out.println(emp2);
sqlSession1.close();
}
查看结果
10.2MyBatis的二级缓存
二级缓存是SqlSessionFactory级别,通过同一个SqlSessionFactory创建的SqlSession查询的结果会被缓存;此后若再次执行相同的查询语句,结果就会从缓存中获取。
二级缓存开启的条件:
< a >.在核心配置文件中,设置全局配置属性cacheEnabled=“true” ,该属性,默认为true,不需要设置。
<settings>
<setting name="cacheEnabled" value="true"/>
</settings>
< b >.在mapper映射文件中设置标签
<cache/>
< c >.二级缓存必须在SqlSession关闭或提交之后有效
sqlSession1.close();
< d >.查询的数据所转换的实体类类型必须实现序列化的接口
public class Emp implements Serializable {}
学习了上面的知识点之后,我们一起来看下二级缓存。
在核心配置文件中添加语句(可以省略)
<setting name="cacheEnabled" value="true"/>
在CacheMapper.xml中新加语句
添加缓存开启语句
在测试类CacheMapperTest.java中添加方法测试
@Test
public void testCache() throws IOException {
InputStream is = Resources.getResourceAsStream("mybatis-config.xml");
SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(is);
SqlSession sqlSession1 = sqlSessionFactory.openSession(true);
CacheMapper mapper1 = sqlSession1.getMapper(CacheMapper.class);
Emp emp1 = mapper1.getEmpById(1);
System.out.println("emp1 =" + emp1);
SqlSession sqlSession2 = sqlSessionFactory.openSession(true);
CacheMapper mapper2 = sqlSession2.getMapper(CacheMapper.class);
Emp emp2 = mapper2.getEmpById(1);
System.out.println("emp2 =" + emp2);
}
查询结果
看到查询结果是去数据库查询了2次,说明二级缓存还没有生效,原来是sqlSession我们还没有关闭,那我们关闭一下。
@Test
public void testCache() throws IOException {
InputStream is = Resources.getResourceAsStream("mybatis-config.xml");
SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(is);
SqlSession sqlSession1 = sqlSessionFactory.openSession(true);
CacheMapper mapper1 = sqlSession1.getMapper(CacheMapper.class);
Emp emp1 = mapper1.getEmpById(1);
System.out.println("emp1 =" + emp1);
SqlSession sqlSession2 = sqlSessionFactory.openSession(true);
CacheMapper mapper2 = sqlSession2.getMapper(CacheMapper.class);
Emp emp2 = mapper2.getEmpById(1);
System.out.println("emp2 =" + emp2);
sqlSession1.close();
sqlSession2.close();
}
执行测试类,发现报错。
org.apache.ibatis.cache.CacheException: Error serializing object. Cause: java.io.NotSerializableException: com.atguigu.mybatis.pojo.Emp
自定义类Emp没有实现序列化,那我们将Emp进行实现
快捷产生序列化的版本号
package com.atguigu.mybatis.pojo;
import java.io.Serializable;
/**
* @ClassName: Emp
* @Description:
* @Author: wty
* @Date: 2023/1/7
*/
public class Emp implements Serializable {
private static final long serialVersionUID = -936807110083368555L;
private Integer empId;
private String empName;
private Integer age;
private String gender;
public Emp() {
}
public Emp(Integer empId, String empName, Integer age, String gender) {
this.empId = empId;
this.empName = empName;
this.age = age;
this.gender = gender;
}
public Integer getEmpId() {
return empId;
}
public void setEmpId(Integer empId) {
this.empId = empId;
}
public String getEmpName() {
return empName;
}
public void setEmpName(String empName) {
this.empName = empName;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public String getGender() {
return gender;
}
public void setGender(String gender) {
this.gender = gender;
}
@Override
public String toString() {
return "Emp{" +
"empId=" + empId +
", empName='" + empName + '\'' +
", age=" + age +
", gender='" + gender + '\'' +
'}';
}
}
这里更改测试类中的方法
@Test
public void testCache() throws IOException {
InputStream is = Resources.getResourceAsStream("mybatis-config.xml");
SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(is);
SqlSession sqlSession1 = sqlSessionFactory.openSession(true);
CacheMapper mapper1 = sqlSession1.getMapper(CacheMapper.class);
Emp emp1 = mapper1.getEmpById(1);
System.out.println("emp1 =" + emp1);
sqlSession1.close();
SqlSession sqlSession2 = sqlSessionFactory.openSession(true);
CacheMapper mapper2 = sqlSession2.getMapper(CacheMapper.class);
Emp emp2 = mapper2.getEmpById(1);
System.out.println("emp2 =" + emp2);
sqlSession2.close();
}
查看运行结果
使二级缓存失效的情况: 两次查询之间执行了任意的增删改,会使一级和二级缓存同时失效
这样便实现了MyBatis的二级缓存。
而如果想让二级缓存失效我们尝试用增删改放在两次查询的中间
修改CacheMapperTest.java
@Test
public void testCache() throws IOException {
InputStream is = Resources.getResourceAsStream("mybatis-config.xml");
SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(is);
SqlSession sqlSession1 = sqlSessionFactory.openSession(true);
CacheMapper mapper1 = sqlSession1.getMapper(CacheMapper.class);
Emp emp1 = mapper1.getEmpById(1);
System.out.println("emp1 =" + emp1);
// 二级缓存失效
Emp emp = new Emp(null, "朱八", 26, "男");
int i = mapper1.insertEmp(emp);
System.out.println("插入了" + i + "条");
sqlSession1.close();
SqlSession sqlSession2 = sqlSessionFactory.openSession(true);
CacheMapper mapper2 = sqlSession2.getMapper(CacheMapper.class);
Emp emp2 = mapper2.getEmpById(1);
System.out.println("emp2 =" + emp2);
sqlSession2.close();
}
查询结果
这第二次查询还是查询了数据库,说明增删改,清空了二级缓存,需要重新查询数据库。
10.3二级缓存的相关配置
在mapper配置文件中添加的cache标签可以设置一些属性:
①eviction属性:缓存回收策略,默认的是 LRU。
LRU(Least Recently Used) – 最近最少使用的:移除最长时间不被使用的对象。
FIFO(First in First out) – 先进先出:按对象进入缓存的顺序来移除它们。
SOFT – 软引用:移除基于垃圾回收器状态和软引用规则的对象。
WEAK – 弱引用:更积极地移除基于垃圾收集器状态和弱引用规则的对象。
②flushInterval属性:刷新间隔,单位毫秒。
默认情况是不设置,也就是没有刷新间隔,缓存仅仅调用语句时刷新 ③size属性:引用数目,正整数。
代表缓存最多可以存储多少个对象,太大容易导致内存溢出
④readOnly属性:只读, true/false
true:只读缓存;会给所有调用者返回缓存对象的相同实例。因此这些对象不能被修改。这提供了很重要的性能优势。
false:读写缓存;会返回缓存对象的拷贝(通过序列化)。这会慢一些,但是安全,因此默认是 false。
10.4MyBatis缓存查询的顺序
从大范围到小范围即(sqlSessionFactory 二级缓存→ SqlSession一级缓存)
先查询二级缓存,因为二级缓存中可能会有其他程序已经查出来的数据,可以拿来直接使用。
如果二级缓存没有命中,再查询一级缓存
如果一级缓存也没有命中,则查询数据库
SqlSession关闭之后,一级缓存中的数据会写入二级缓存
10.5整合第三方缓存EHCache
10.5.1添加依赖
在pom.xml中添加依赖
<!-- Mybatis EHCache整合包 -->
<dependency>
<groupId>org.mybatis.caches</groupId>
<artifactId>mybatis-ehcache</artifactId>
<version>1.2.1</version>
</dependency>
<!-- slf4j日志门面的一个具体实现 -->
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.2.3</version>
</dependency>
简单讲述
10.5.2各jar包功能
jar包名称 | 作用 |
---|---|
mybatis-ehcache | Mybatis和EHCache的整合包 |
ehcache | EHCache核心包 |
slf4j-api | SLF4J日志门面包 |
logback-classic | 支持SLF4J门面接口的一个具体实现 |
10.5.3创建EHCache的配置文件ehcache.xml
<?xml version="1.0" encoding="utf-8" ?>
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="../config/ehcache.xsd">
<!-- 磁盘保存路径 -->
<diskStore path="F:\javawebwork\ehcache"/>
<defaultCache
maxElementsInMemory="1000"
maxElementsOnDisk="10000000"
eternal="false"
overflowToDisk="true"
timeToIdleSeconds="120"
timeToLiveSeconds="120"
diskExpiryThreadIntervalSeconds="120"
memoryStoreEvictionPolicy="LRU">
</defaultCache>
</ehcache>
10.5.4设置二级缓存的类型
在CacheMapper.xml中设置
<cache type="org.mybatis.caches.ehcache.EhcacheCache"/>
10.5.5加入logback日志
存在SLF4J时,作为简易日志的log4j将失效,此时我们需要借助SLF4J的具体实现logback来打印日志。 创建logback的配置文件logback.xml
<?xml version="1.0" encoding="UTF-8"?>
<configuration debug="true">
<!-- 指定日志输出的位置 -->
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<!-- 日志输出的格式 -->
<!-- 按照顺序分别是: 时间、日志级别、线程名称、打印日志的类、日志主体内容、换行
-->
<pattern>[%d{HH:mm:ss.SSS}] [%-5level] [%thread] [%logger]
[%msg]%n
</pattern>
</encoder>
</appender>
<!-- 设置全局日志级别。日志级别按顺序分别是: DEBUG、INFO、WARN、ERROR -->
<!-- 指定任何一个日志级别都只打印当前级别和后面级别的日志。 -->
<root level="DEBUG">
<!-- 指定打印日志的appender,这里通过“STDOUT”引用了前面配置的appender -->
<appender-ref ref="STDOUT"/>
</root>
<!-- 根据特殊需求指定局部日志级别 -->
<logger name="com.atguigu.mybatis.mapper" level="DEBUG"/>
</configuration>
修改CacheMapperTest.java
@Test
public void testCache() throws IOException {
InputStream is = Resources.getResourceAsStream("mybatis-config.xml");
SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(is);
SqlSession sqlSession1 = sqlSessionFactory.openSession(true);
CacheMapper mapper1 = sqlSession1.getMapper(CacheMapper.class);
Emp emp1 = mapper1.getEmpById(1);
System.out.println("emp1 =" + emp1);
sqlSession1.close();
SqlSession sqlSession2 = sqlSessionFactory.openSession(true);
CacheMapper mapper2 = sqlSession2.getMapper(CacheMapper.class);
Emp emp2 = mapper2.getEmpById(1);
System.out.println("emp2 =" + emp2);
sqlSession2.close();
}
查询结果
缓存位置
10.5.6EHCache配置文件说明
属性名 | 是否必须 | 作用 |
---|---|---|
maxElementsInMemory | 是 | 在内存中缓存的element的最大数目 |
maxElementsOnDisk | 是 | 在磁盘上缓存的element的最大数目,若是0表示无穷大 |
eternal | 是 | 设定缓存的elements是否永远不过期。 如果为true,则缓存的数据始终有效, 如果为false那么还要根据timeToIdleSeconds、timeToLiveSeconds判断 |
overflowToDisk | 是 | 设定当内存缓存溢出的时候是否将过期的element缓存到磁盘上 |
timeToIdleSeconds | 否 | 当缓存在EhCache中的数据前后两次访问的时间超过timeToIdleSeconds的属性取值时, 这些数据便会删除,默认值是0,也就是可闲置时间无穷大 |
timeToLiveSeconds | 否 | 缓存element的有效生命期,默认是0.,也就是element存活时间无穷大 |
diskSpoolBufferSizeMB | 否 | DiskStore(磁盘缓存)的缓存区大小。默认是30MB。每个Cache都应该有自己的一个缓冲区 |
diskPersistent | 否 | 在VM重启的时候是否启用磁盘保存EhCache中的数据,默认是false。 |
diskExpiryThreadIntervalSeconds | 否 | 磁盘缓存的清理线程运行间隔,默认是120秒。每隔120s, 相应的线程会进行一次EhCache中数据的清理工作 |
memoryStoreEvictionPolicy | 否 | 当内存缓存达到最大,有新的element加入的时候, 移除缓存中element的策略。 默认是LRU (最近最少使用),可选的有LFU (最不常使用)和FIFO (先进先出) |
11.MyBatis的逆向工程
正向工程:先创建Java实体类,由框架负责根据实体类生成数据库表。 Hibernate是支持正向工程的。
逆向工程:先创建数据库表,由框架负责根据数据库表,反向生成如下资源:
Java实体类
Mapper接口
Mapper映射文件
注意:逆向工程只能针对单表操作,多表不支持
11.1创建逆向工程的步骤
新创建一个Module
GroupId:com.atguigu.mybatis
Name:mybatis-mbg
(1)添加依赖和插件
在pom.xml中添加依赖
这里要注意mysql的版本,配置成和自己安装的一致即可。
<!-- 依赖MyBatis核心包 -->
<dependencies>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.7</version>
</dependency>
<!-- junit测试 -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<!-- log4j日志 -->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.20</version>
</dependency>
</dependencies>
<!-- 控制Maven在构建过程中相关配置 -->
<build>
<!-- 构建过程中用到的插件 -->
<plugins>
<!-- 具体插件,逆向工程的操作是以构建过程中插件形式出现的 -->
<plugin>
<groupId>org.mybatis.generator</groupId>
<artifactId>mybatis-generator-maven-plugin</artifactId>
<version>1.3.0</version>
<!-- 插件的依赖 -->
<dependencies>
<!-- 逆向工程的核心依赖 -->
<dependency>
<groupId>org.mybatis.generator</groupId>
<artifactId>mybatis-generator-core</artifactId>
<version>1.3.2</version>
</dependency>
<!-- MySQL驱动 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.20</version>
</dependency>
</dependencies>
</plugin>
</plugins>
</build>
添加打包方式
<packaging>jar</packaging>
(2)创建MyBatis的核心配置文件
(3)创建逆向工程的配置文件
文件名必须是:generatorConfig.xml
这里创建的是MyBatis3Simple: 清新简洁版
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE generatorConfiguration
PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
"http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">
<generatorConfiguration>
<!--
targetRuntime: 执行生成的逆向工程的版本
MyBatis3Simple: 生成基本的CRUD(清新简洁版)
MyBatis3: 生成带条件的CRUD(奢华尊享版)
-->
<context id="DB2Tables" targetRuntime="MyBatis3Simple">
<!-- 数据库的连接信息 -->
<jdbcConnection driverClass="com.mysql.jdbc.Driver"
connectionURL="jdbc:mysql://localhost:3306/ssm?"
userId="root"
password="hsp">
</jdbcConnection>
<!-- javaBean的生成策略-->
<javaModelGenerator targetPackage="com.atguigu.mybatis.pojo"
targetProject=".\src\main\java">
<!-- enableSubPackages 设置成true表示可以使用子包 -->
<property name="enableSubPackages" value="true"/>
<!-- 把数据库字段的前后空格去掉生成实体类的属性 -->
<property name="trimStrings" value="true"/>
</javaModelGenerator>
<!-- SQL映射文件的生成策略 -->
<sqlMapGenerator targetPackage="com.atguigu.mybatis.mapper"
targetProject=".\src\main\resources">
<property name="enableSubPackages" value="true"/>
</sqlMapGenerator>
<!-- Mapper接口的生成策略 -->
<javaClientGenerator type="XMLMAPPER"
targetPackage="com.atguigu.mybatis.mapper" targetProject=".\src\main\java">
<property name="enableSubPackages" value="true"/>
</javaClientGenerator>
<!-- 逆向分析的表 -->
<!-- tableName设置为*号,可以对应所有表,此时不写domainObjectName -->
<!-- domainObjectName属性指定生成出来的实体类的类名 -->
<table tableName="t_emp" domainObjectName="Emp"/>
<table tableName="t_dept" domainObjectName="Dept"/>
</context>
</generatorConfiguration>
(4)执行MBG插件的generate目标
配置完依赖多了插件
双击插件
最后创建成功即可
(5)效果
看Mapper接口中有5个方法
package com.atguigu.mybatis.mapper;
import com.atguigu.mybatis.pojo.Emp;
import java.util.List;
public interface EmpMapper {
/**
* This method was generated by MyBatis Generator.
* This method corresponds to the database table t_emp
*
* @mbggenerated Sun Jan 08 13:28:24 CST 2023
*/
int deleteByPrimaryKey(Integer empId);
/**
* This method was generated by MyBatis Generator.
* This method corresponds to the database table t_emp
*
* @mbggenerated Sun Jan 08 13:28:24 CST 2023
*/
int insert(Emp record);
/**
* This method was generated by MyBatis Generator.
* This method corresponds to the database table t_emp
*
* @mbggenerated Sun Jan 08 13:28:24 CST 2023
*/
Emp selectByPrimaryKey(Integer empId);
/**
* This method was generated by MyBatis Generator.
* This method corresponds to the database table t_emp
*
* @mbggenerated Sun Jan 08 13:28:24 CST 2023
*/
List<Emp> selectAll();
/**
* This method was generated by MyBatis Generator.
* This method corresponds to the database table t_emp
*
* @mbggenerated Sun Jan 08 13:28:24 CST 2023
*/
int updateByPrimaryKey(Emp record);
}
下面创建一下MyBatis3: 奢华尊享版
更改generatorConfig.xml
<context id="DB2Tables" targetRuntime="MyBatis3">
删除逆向工程创建的包和类
重新运行插件
运行结果,查看
11.2QBC查询
创建MBGTest.java测试类
在MBGTest.java中添加方法
测试根据主键查询
@Test
public void testMBG() {
SqlSession sqlSession = SqlSessionUtil.getSqlSession();
EmpMapper mapper = sqlSession.getMapper(EmpMapper.class);
Emp emp = mapper.selectByPrimaryKey(1);
System.out.println(emp);
sqlSession.close();
}
执行MBGTest.java结果
给Emp添加toString()方法
执行结果
在MBGTest.java中添加方法——
测试无条件查询
@Test
public void testMBG1() {
SqlSession sqlSession = SqlSessionUtil.getSqlSession();
EmpMapper mapper = sqlSession.getMapper(EmpMapper.class);
List<Emp> list = mapper.selectByExample(null);
list.forEach(System.out::println);
sqlSession.close();
}
条件为null的时候,相当于查询全部
测试根据条件查询
这里需要创建EmpExample对象
在MBGTest.java中添加方法
根据条件查询:一个叫张三的员工
@Test
public void testMBG2() {
SqlSession sqlSession = SqlSessionUtil.getSqlSession();
EmpMapper mapper = sqlSession.getMapper(EmpMapper.class);
// 根据条件查询:一个叫张三的员工
EmpExample empExample = new EmpExample();
empExample.createCriteria().andEmpNameEqualTo("张三");
List<Emp> list = mapper.selectByExample(empExample);
list.forEach(System.out::println);
sqlSession.close();
}
查询结果
多条件查询
多个and查询
如果我们在员工是张三的基础上,加入查询条件:年龄大于等于20岁,那我们只需要继续在后面拼接即可。
@Test
public void testMBG2() {
SqlSession sqlSession = SqlSessionUtil.getSqlSession();
EmpMapper mapper = sqlSession.getMapper(EmpMapper.class);
// 根据条件查询:一个叫张三的员工
EmpExample empExample = new EmpExample();
empExample.createCriteria().andEmpNameEqualTo("张三").andAgeGreaterThanOrEqualTo(20);
List<Emp> list = mapper.selectByExample(empExample);
list.forEach(System.out::println);
sqlSession.close();
}
查询结果
多个or查询
那如果掺杂了or怎么办呢,比如我们需要查询叫张三,年龄大于等于20岁,或者性别是女的员工
修改MBGTest.java类的方法
@Test
public void testMBG2() {
SqlSession sqlSession = SqlSessionUtil.getSqlSession();
EmpMapper mapper = sqlSession.getMapper(EmpMapper.class);
// 根据条件查询:一个叫张三的员工
EmpExample empExample = new EmpExample();
empExample.createCriteria().andEmpNameEqualTo("张三").andAgeGreaterThanOrEqualTo(20);
empExample.or().andGenderEqualTo("女");
List<Emp> list = mapper.selectByExample(empExample);
list.forEach(System.out::println);
sqlSession.close();
}
查询结果
选择性修改
Emp.java添加有参构造
在MBGTest.java中添加方法
@Test
public void testMBG4() {
SqlSession sqlSession = SqlSessionUtil.getSqlSession();
EmpMapper mapper = sqlSession.getMapper(EmpMapper.class);
// 根据选择性修改:
Emp emp = new Emp(14, "小丽", null, "女");
EmpExample empExample = new EmpExample();
empExample.createCriteria().andEmpNameEqualTo("张三").andAgeGreaterThanOrEqualTo(20);
int i = mapper.updateByPrimaryKeySelective(emp);
System.out.println("更新了" + i + "条数据");
sqlSession.close();
}
因为是选择性修改,null的值不会替换修改
普通修改
在MBGTest.java中添加方法
@Test
public void testMBG3() {
SqlSession sqlSession = SqlSessionUtil.getSqlSession();
EmpMapper mapper = sqlSession.getMapper(EmpMapper.class);
// 根据主键修改:
Emp emp = new Emp(14, "小美", 26, "女");
EmpExample empExample = new EmpExample();
empExample.createCriteria().andEmpNameEqualTo("张三").andAgeGreaterThanOrEqualTo(20);
int i = mapper.updateByPrimaryKey(emp);
System.out.println("更新了" + i + "条数据");
sqlSession.close();
}
修改结果
12分页插件
limit index,pageSize
pageSize:每页显示的条数
pageNum:当前页的页码
index:当前页的起始索引,index=(pageNum-1)*pageSize
count:总记录数
totalPage:总页数
totalPage = count / pageSize;
if(count % pageSize != 0){
totalPage += 1;
}
pageSize=4,pageNum=1,index=0 limit 0,4
pageSize=4,pageNum=3,index=8 limit 8,4
pageSize=4,pageNum=6,index=20 limit 20,4
导航分页:
首页 上一页 2 3 4 5 6 下一页 末页
12.1分页插件的使用步骤
(1)添加依赖
在pom.xml中添加依赖
<!-- 分页插件 -->
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper</artifactId>
<version>5.2.0</version>
</dependency>
(2)配置分页插件
在MyBatis的核心配置文件中配置插件
在mybatis-config.xml中配置
<plugins>
<!--设置分页插件-->
<plugin interceptor="com.github.pagehelper.PageInterceptor"></plugin>
</plugins>
这里的全类名如果不太好找可以使用IDEA自带的全类名搜索:快捷键Ctrl+Shift+a
在搜索栏点选class然后搜索PageInterceptor
拷贝全类名即可
新建测试类PageTest.java来测试分页功能
去sqlyog中将表t_emp截断,重新插入一些数据,30条
12.2分页插件的使用
< a >在查询功能之前使用PageHelper.startPage(int pageNum, int pageSize)开启分页功能。
pageNum:当前页的页码
pageSize:每页显示的条数
在测试类PagTest.java中添加方法
@Test
public void testPage() {
SqlSession sqlSession = SqlSessionUtil.getSqlSession();
EmpMapper mapper = sqlSession.getMapper(EmpMapper.class);
// 分页查询
// 开启分页功能
PageHelper.startPage(1, 4);
List<Emp> list = mapper.selectByExample(null);
list.forEach(System.out::println);
sqlSession.close();
}
查询结果:
分析一下查询结果:
打印一下page值
@Test
public void testPage() {
SqlSession sqlSession = SqlSessionUtil.getSqlSession();
EmpMapper mapper = sqlSession.getMapper(EmpMapper.class);
// 分页查询
// list前开启分页功能
Page<Object> page = PageHelper.startPage(1, 4);
List<Emp> list = mapper.selectByExample(null);
list.forEach(System.out::println);
System.out.println(page);
sqlSession.close();
}
输出结果:
注意Page是继承自ArrayList
这里可以处结论可以自定义接口返回值Page获取查询结果
< b >在查询获取list集合之后,使用PageInfo pageInfo = new PageInfo<>(List list, int navigatePages)获取分页相关数据。
list:分页之后的数据
navigatePages:导航分页的页码数
修改PageTest.java中的方法
/**
* PageInfo{
* pageNum=4, pageSize=4, size=4, 当前是第4页,此页中有4条数据
* startRow=13, endRow=16, 当前页的数据是从第13行数据到16条数据
* total=30, pages=8, 所有页一共30条数据,一共8页。符合30/4 = 7……2 则总页数是7 + 1 = 8
* list=Page{count=true, pageNum=4, pageSize=4, startRow=12, endRow=16, total=30, pages=8, reasonable=false, pageSizeZero=false}[Emp{empId=13, empName='a', age=null, gender='null', deptId=null}, Emp{empId=14, empName='a', age=null, gender='null', deptId=null}, Emp{empId=15, empName='a', age=null, gender='null', deptId=null}, Emp{empId=16, empName='a', age=null, gender='null', deptId=null}],
* prePage=3, nextPage=5, 当前页是第4页,所以上一页的页码是3,后一页的页码是5
* isFirstPage=false, isLastPage=false, 是否是第一页,是否是最后一夜
* hasPreviousPage=true, hasNextPage=true, 是否有上一页,是否有下一页
* navigatePages=4, 当前页
* navigateFirstPage=2,导航分页的初始页
* navigateLastPage=5, 导航分页的最终页
* navigatepageNums=[2, 3, 4, 5]}导航分页的页码
*/
@Test
public void testPage1() {
SqlSession sqlSession = SqlSessionUtil.getSqlSession();
EmpMapper mapper = sqlSession.getMapper(EmpMapper.class);
// 分页查询
Page<Object> page = PageHelper.startPage(4, 4);
List<Emp> list = mapper.selectByExample(null);
// list后开启分页功能
// navigatePages:导航分页的个数,比如设置4,导航分页就是2,3,4,5
// 比如设置5,导航分页是2,3,4,5,6
PageInfo<Emp> pageInfo = new PageInfo<>(list, 5);
list.forEach(System.out::println);
System.out.println(pageInfo);
sqlSession.close();
}
查询结果:
< c >分页相关数据
PageInfo{
pageNum=8, pageSize=4, size=2, startRow=29, endRow=30, total=30, pages=8,
list=Page{count=true, pageNum=8, pageSize=4, startRow=28, endRow=32, total=30,
pages=8, reasonable=false, pageSizeZero=false},
prePage=7, nextPage=0, isFirstPage=false, isLastPage=true, hasPreviousPage=true,
hasNextPage=false, navigatePages=5, navigateFirstPage4, navigateLastPage8,
navigatepageNums=[4, 5, 6, 7, 8]
}
pageNum:当前页的页码
pageSize:每页显示的条数
size:当前页显示的真实条数
total:总记录数
pages:总页数
prePage:上一页的页码
nextPage:下一页的页码
isFirstPage/isLastPage:是否为第一页/最后一页
hasPreviousPage/hasNextPage:是否存在上一页/下一页
navigatePages:导航分页的页码数
navigatepageNums:导航分页的页码,[1,2,3,4,5]