轻量级,性能出色
SQL 和 Java 编码分开,功能边界清晰。Java代码专注业务、SQL语句专注数据
开发效率稍逊于HIbernate,但是完全能够接受
一:什么是POJO
POJO的名称有多种,pure old java object 、plain ordinary java object 等。
按照Martin Fowler的解释是“Plain Old Java Object”,从字面上翻译为“纯洁老式的java对象”,但大家都使用“简单java对象”来称呼它。
POJO的内在含义是指那些没有从任何类继承、也没有实现任何接口,更没有被其它框架侵入的java对象。
二:为什么会有POJO?
主要是Java的开发者被EJB的繁杂搞怕了,大家经过反思,又回归“纯洁老式”的JavaBean,即有无参构造函数,每个字段都有getter和setter的java类。
无参构造器必须要有
MyBatis中的mapper接口相当于以前的dao。但是区别在于,mapper仅仅是接口,我们不需要
提供实现类。
DAO层叫数据访问层,全称为data access object,某个DAO一定是和数据库的某一张表一一对应的,其中封装了CRUD(增加Create、检索Retrieve、更新Update和删除Delete)基本操作,DAO只做原子操作。无论多么复杂的查询,dao只是封装增删改查。至于增删查改如何去实现一个功能,dao是不管的
起名规则:POJO的名字 + Mapper
MyBatis映射文件用于编写SQL,访问以及操作表中的数据
MyBatis映射文件存放的位置是src/main/resources/mappers目录下
相关概念:ORM(Object Relationship Mapping)对象关系映射。
对象:Java的实体类对象
关系:关系型数据库
映射:二者之间的对应关系
命名规则:表所对应的实体类的类名+Mapper.xml(最好是一个mapper接口及其对应一个配置文件的名字相同,即,有一个Java文件时UserMapper.java,对应一个UserMapper.xml)
因此一个映射文件对应一个实体类,对应一张表的操作,对应一个mapper接口
mapper接口中的一个方法,对应映射文件中的一个SQL语句
MyBatis中可以面向接口操作数据,要保证两个一致:
1、mapper接口的全类名和映射文件的命名空间(namespace)保持一致
2、mapper接口中方法的方法名和映射文件中编写SQL的标签的id属性保持一致
Mybatis有两个重要文件:核心文件和映射文件
核心文件用于连接数据库
映射文件用于操作数据库
映射文件中写的是SQL语句
public interface UserMapper {/*** 添加用户信息*/int insertUser();
}
package com.atguigu.mybatis;import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.Test;
import com.atguigu.mybatis.mapper.UserMapper;import java.io.IOException;
import java.io.InputStream;public class MyBatisTest {@Testpublic void testInsert() throws IOException {// 获取核心配置文件的输入流(核心配置文件中又注入了映射文件,所以获取核心配置文件即可)InputStream resourceAsStream = Resources.getResourceAsStream("mybatis-config.xml");// 获取SqlSessionFactoryBuilder 对象 -> 工厂构建器SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();// 创建 SqlSessionFactory -> 创建会话SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(resourceAsStream);// 获取sqlSession -> MyBatis 提供的操作数据库的对象(不会自动提交事务)SqlSession sqlSession = sqlSessionFactory.openSession();//获取sqlSession -> MyBatis 提供的操作数据库的对象(可以自动提交事务)//SqlSession sqlSession = sqlSessionFactory.openSession(true);// 获得Mapper接口的代理类 -> 操纵Mapper类执行数据库操作(UserMapper是一个接口,不能直接实例化,所以通过这种方式创建其对象)UserMapper userMapper = sqlSession.getMapper(UserMapper.class);// 执行SQL操作Integer rows = userMapper.insertUser();System.out.println("rows = " + rows);// 提交事务 -> 事务是默认开启的(不然数据库中并没有这条记录)sqlSession.commit();// 关闭资源sqlSession.close();}
}
SqlSession:代表Java程序和数据库之间的会话。(HttpSession是Java程序和浏览器之间的会话)
SqlSessionFactory:是“生产”SqlSession的“工厂”。
工厂模式:如果创建某一个对象,使用的过程基本固定,那么我们就可以把创建这个对象的
日志的xml文件名字必须是——log4j.xml
FATAL(致命)>ERROR(错误)>WARN(警告)>INFO(信息)>DEBUG(调试)
从左到右打印的内容越来越详细(级别越来越低)
核心配置文件中的标签必须按照固定的顺序:
properties?,settings?,typeAliases?,typeHandlers?,objectFactory?,objectWrapperFactory?,refl
ectorFactory?,plugins?,environments?,databaseIdProvider?,mappers?
typeAlias:设置某个类型的别名
属性:
type:设置需要设置别名的类型
alias:设置某个类型的别名,若不设置该属性,那么该类型拥有默认的别名,即类名且不区分大小写
environments:配置多个连接数据库的环境
可以配置多个环境,比如测试环境和开发环境 ; 使用id区分,不能重复。
属性:
default:设置默认使用的环境的id
transactionManager:设置事务管理方式
属性:
type=“JDBC|MANAGED”
JDBC:表示当前环境中,执行SQL时,使用的是JDBC中原生的事务管理方式,事务的提交或回滚需要手动处理
MANAGED:被管理,例如Spring
dataSource:配置数据源
属性:
type:设置数据源的类型
type=“POOLED|UNPOOLED|JNDI”
POOLED:表示使用数据库连接池缓存数据库连接
UNPOOLED:表示不使用数据库连接池
JNDI:表示使用上下文中的数据源
例子在前面的代码中
总的配置文件:
在 Mapper.xml 文件中使用:
添加:
insert into t_user values(null,'admin','123456',23,'男')
删除:
delete from t_user where id = 7
修改:
update t_user set username='ybc',password='123' where id = 6
查询:
注意:
查询的标签select必须设置属性resultType或resultMap,用于设置实体类和数据库表的映射
关系
resultType:自动映射,用于属性名和表中字段名一致的情况,resultType可以直接返回给出的返回值类型(意思是返回值类型)
resultMap:自定义映射,用于一对多或多对一或字段名和属性名不一致的情况,返回值是自定义实体类的情况(意思是自定义映射)
MyBatis获取参数值的两种方式:${}和#{}
${}的本质就是字符串拼接,#{}的本质就是占位符赋值
${}使用字符串拼接的方式拼接sql,若为字符串类型或日期类型的字段进行赋值时,需要手动加单引
号;但是#{}使用占位符赋值的方式拼接sql,此时为字符串类型或日期类型的字段进行赋值时,
可以自动添加单引号
若mapper接口中的方法参数为单个的字面量类型
此时可以使用{}和#{}以任意的名称获取参数的值,注意{}需要手动加单引号
其实大括号中的名字不一定非得是变量名,任意的名字都可以成功获取,不过建议使用参数名让其变得有意义
若mapper接口中的方法参数为多个时:
此时MyBatis会自动将这些参数放在一个map集合中,以arg0,arg1…为键,以参数为值;
以param1,param2…为键,以参数为值;
因此只需要通过${}和#{}访问map集合的键就可以获取相对应的值,注意 ${}需要手动加单引号
使用param方式:(使用arg0……就是将大括号中的param1改成arg0,param2改成arg1……即可)
若mapper接口中的方法需要的参数为多个时,此时可以手动创建map集合,将这些数据放在
map中
只需要通过{}和#{}访问map集合的键就可以获取相对应的值,注意${}需要手动加单引号
在select中设置的键值是username和password,因为在test方法中,在put时,制定了map集合中两个键值的名字:username和password,和上一种情况相比,就是,这次我们是通过put对map进行手动添加,而且自定义了键值的名称,上一种情况是,机器自动将我们的参数放到map中,所以只能使用机器定义的键值名称:arg0……param1等
若mapper接口中的方法参数为实体类对象(如下的User)时,此时可以使用{}和#{},通过访问实体类对象中的属性名获取属性值,注意{}需要手动加单引号
注意,属性和我们在java中编写的private int age 等内容没有关系,而是和get、set方法有关系,如果一个java类中,没有设置相应的age等成员变量,但是有其对应的get、set方法,不会阻碍我们获取相应的成员变量。属性就是将这两个方法的get、set去掉,剩余部分变成小写。
总结:属性,只和类中的get、set方法有关(取值找get,赋值找set),与成员变量无关!
User类的结构:
id设置为null是想让他自增
可以通过@Param注解标识mapper接口中的方法参数此时,会将这些参数放在map集合中,以@Param注解的value属性值为键,以参数为值;以param1,param2…为键,以参数为值;只需要通过${}和#{}访问map集合的键就可以获取相对应的值,注意 ${}需要手动加单引号
与第二种情况比较,可以自定义键值,与第三种情况比较,可以不需要手动向map中添加
想要访问参数的值,需要先访问他对应的键,所以#{}中的内容是键,也就是@Param括号中的内容
/**
* 根据用户id查询用户信息
* @param id
* @return
*/
User getUserById(@Param("id") int id);
这里使用@Param是因为,字面量在查询的时候可以通过任意的内容来查询,所以这里制定用id查询
当查询的数据为多条时,不能使用实体类作为返回值,否则会抛出异常TooManyResultsException;
但是若查询的数据只有一条,可以使用实体类或集合作为返回值
/**
* 查询所有用户信息
* @return
*/
List getUserList();
/**
* 查询用户的总记录数
* @return
* 在MyBatis中,对于Java中常用的类型都设置了类型别名
* 例如: java.lang.Integer的别名:int|integer
* 例如: int的别名:_int|_integer
* 例如: String的别名:string
* 例如: Map的别名:map,List的别名:list
*/
int getCount();
举例:加入我们想要查询员工数据表的最高工资、最低工资和平均工资,这时没有其对应的实体类,那应该将返回的数据存放成什么类型呢?
其实实体类和Map都是通过键值对,两者的最大区别就是,实体类中的键值对是固定的,只有设置好的那些,比如name、age、email等,查询为一个实体类必须要字段名和属性名一致,但是Map中没有固定的键,想查啥都行
/**
* 根据用户id查询用户信息为map集合
* @param id
* @return
*/
Map getUserToMap(@Param("id") int id);
password=123456, sex=男 , id=1, age=23, username=admin}-->
注意:如果查询的内容中,有字段的值为空,即null,该字段的内容是不会放在map中的。
注意:一条数据对应一个map;若有多条数据,就会产生多个map集合,不能只用一个map接受,否则报错
/**
* 查询所有用户信息为map集合
* @return
* 将表中的数据以map集合的方式查询,一条数据对应一个map;若有多条数据,就会产生多个map集合,此
时可以将这些map放在一个list集合中获取
*/
List
/**
* 查询所有用户信息为map集合
* @return
* 将表中的数据以map集合的方式查询,一条数据对应一个map;若有多条数据,就会产生多个map集合,并
且最终要以一个map的方式返回数据,此时需要通过@MapKey注解设置map集合的键,值是每条数据所对应的
map集合
*/
@MapKey("id")
Map getAllUserToMap();
1={password=123456, sex=男, id=1, age=23, username=admin},2={password=123456, sex=男, id=2, age=23, username=张三},3={password=123456, sex=男, id=3, age=23, username=张三}
}
-->
/**
* 测试模糊查询
* @param mohu
* @return
*/
List testMohu(@Param("mohu") String mohu);
1、like '%${mohu}%'中 ${mohu},由于 ${}会解释称占位符?,但是因为?是在单引号中,所以并不会将它作为占位符使用,而是看作字符串的一部分,会报错
2、concat是拼接字符串的函数
3、用双引号的方式使用最多
/**
* 批量删除
* @param ids
* @return
*/
int deleteMore(@Param("ids") String ids);
delete from t_user where id in (${ids})
这里用到 ${}是因为如果用#{},时会自动添加单引号的,但是在sql语句中:delete from t_user where id in (‘9,10’)是错误的,正确的写法是delete from t_user where id in (9,10)——删除id为9和10的数据。
/**
* 动态设置表名,查询所有的用户信息
* @param tableName
* @return
*/
List getAllUser(@Param("tableName") String tableName);
同样,表明也是不能加单引号的
场景模拟:
t_clazz(clazz_id,clazz_name)——班级表
t_student(student_id,student_name,clazz_id)——学生表
1、添加班级信息
2、获取新添加的班级的id
3、为班级分配学生,即将某学的班级id修改为新添加的班级的id
/**
* 添加用户信息
* @param user
* @return
* useGeneratedKeys:设置使用自增的主键
* keyProperty:因为增删改有统一的返回值是受影响的行数,因此只能将获取的自增的主键放在传输的参数user对象的某个属性中(将添加的自增的主键为实体类对象的某个属性赋值)
*/
int insertUser(User user);
insert into t_user values(null,#{username},#{password},#{age},#{sex})
若字段名和实体类中的属性名不一致,则可以通过resultMap设置自定义映射(比如数据表中的字段名的命名是是用下划线,而Java中的属性名用的是驼峰的方式命名,两者不能对应上)
处理方法:
1、为表中的每个字段起别名
2、当字段名符合mysql中的命名规则使用下划线,而属性名符合Java的命名规则使用驼峰时,可以在mybatis的配置文件中统一设置一个全局配置,将下划线映射为驼峰。
3、使用ResultMap自定义映射处理:
场景模拟:
查询员工信息以及员工所对应的部门信息
对一,对应的就是一个对象
对多,对应的就是一个集合
Emp实体类中有类型为Dept的属性dept,但是我们想要返回的dept.*里有dept_id和dept_name,这两个字段名并不能和Emp的dept属性进行映射,他们应该和Emp中的dept属性的dept_id和dept_name映射
①查询员工信息
/**
* 通过分步查询查询员工信息
* @param eid
* @return
*/
Emp getEmpByStep(@Param("eid") int eid);
1、这里的association 后面的select跟的是调用的select语句所在的方法的全类名+方法名,可以通过——找到方法——点击右键——Copy Reference就可以获得全类名+方法名
2、column中写的是条件,因为在第二部查询时,用到了一个参数,而这个参数是通过第一部查询获得,column中写的就是这个作为第二部查询的条件的字段
②根据员工所对应的部门id查询部门信息
/**
* 分步查询的第二步: 根据员工所对应的did查询部门信息
* @param did
* @return
*/
Dept getEmpDeptByStep(@Param("did") int did);
分步查询的优点:可以实现延迟加载
但是必须在核心配置文件中设置全局配置信息:
lazyLoadingEnabled:延迟加载的全局开关。当开启时,所有关联对象都会延迟加载
aggressiveLazyLoading:当开启时,任何方法的调用都会加载该对象的所有属性。否则,每个属性会按需加载
此时就可以实现按需加载,获取的数据是什么,就只会执行相应的sql。此时可通过association和collection中的fetchType属性设置当前的分步查询是否使用延迟加载, fetchType=“lazy(延迟加
载)|eager(立即加载)”
fetchType:在开启了延迟加载的环境中,通过设置该属性设置当前分布查询是否使用延迟加载
比如在Dept这个类中,就是多个员工对应一个部门
collection:设置一对多的映射关系
不再使用javaType,因为前面有collection,说明处理的是集合类型,而要用ofType,指明的是集合类型的属性中存储的数据的类型
/**
* 根据部门id查新部门以及部门中的员工信息
* @param did
* @return
*/
Dept getDeptEmpByDid(@Param("did") int did);
①查询部门信息
/**
* 分步查询部门和部门中的员工
* @param did
* @return
*/
Dept getDeptByStep(@Param("did") int did);
②根据部门id查询部门中的所有员工
/**
* 根据部门id查询员工信息
* @param did
* @return
*/
List getEmpListByDid(@Param("did") int did);
Mybatis框架的动态SQL技术是一种根据特定条件动态拼装SQL语句的功能,它存在的意义是为了
解决 拼接SQL语句字符串时的痛点问题。
可以通过判断这个字段是否是null或“”(空字符串),如果是这两个值,说明没有设置对应的条件,如果不是,说明设置了条件
if标签可通过test属性的表达式进行判断,若表达式的结果为true,则标签中的内容会执行;反之
标签中的内容不会执行
可以看出来,我们设置的几个字段都不是null和空字符串,所以应该将这几个条件拼接到select语句中
if 标签中的ename等属性不用#{}也不用${}就可以通过属性名得到
if中存在的问题:
1、以上个例子为例,如果在输入参数时,将name设置为null,那么在select语句中就会出现where后面跟了第二个if标签中的and,但是这种select出现了语法错误。
2、如果这几个字段都是null或空字符串,那select语句最后多出来一个where,让然出现语法错误
where和if一般结合使用:
a>若where标签中的if条件都不满足,则where标签没有任何功能,即不会添加where关键字
b>若where标签中的if条件满足,则where标签会自动添加where关键字,并将条件最前方多余的and去掉(但是内容后多余的end无法去掉)
注意:where标签不能去掉条件最后多余的and
trim用于去掉或添加标签中的内容
常用属性:
prefix:在trim标签中的内容的前面添加某些内容
prefixOverrides:在trim标签中的内容的前面去掉某些内容
suffix:在trim标签中的内容的后面添加某些内容
suffixOverrides:在trim标签中的内容的后面去掉某些内容
choose、when、 otherwise相当于if…else if…else
when最少设置一个,otherwise最多设置一个
只要有一个成立,后面的条件就不在判断
collection:设置要循环的数组或集合
item:用字符串来表示数组或集合中的每一个数据
separator:设置每次循环间数据之间的分隔符
注意:如果前面没有添加@Param,那MyBatis是默认是这个参数是list
insert into t_emp values(null,#{emp.ename},#{emp.age},#{emp.sex},#{emp.email},null)
delete from t_emp whereeid = #{eid}
delete from t_emp where eid in#{eid}
如果参数是list或者数组,MyBatis是默认将参数放在map中
如果前面没有添加@Param,那MyBatis是默认是这个参数是list,如果是数组,那默认是Array
所以简单起见,前面最好都加上@Param
注意:批量添加和批量删除代码中,括号和foreach的位置
不加open和close的批量删除代码:
前面的代码就是因为一个item是一个对象,而我们要去的是对象中的属性,所以写成:#{emp.ename},但是后面的代码只是将id取出来,每一个item就是id值,所以直接写成:#{eid}
open:以……开始
close:以……结束
另外一种方式:
sql片段,可以记录一段公共sql片段,在使用的地方通过include标签进行引入
eid,ename,age,sex,did
select from t_emp
一级缓存是SqlSession级别的,通过同一个SqlSession查询的数据会被缓存,下次查询相同的数据,就会从缓存中直接获取,不会从数据库重新访问
使一级缓存失效的四种情况:
1、不同的SqlSession对应不同的一级缓存
2、同一个SqlSession但是查询条件不同
3、同一个SqlSession两次查询期间执行了任何一次增删改操作
4、同一个SqlSession两次查询期间手动清空了缓存
创建了两个sql语句完全相同的sqlSession:
执行结果:(执行了2次sql语句,第二次不是从缓存中获得数据)
二级缓存是SqlSessionFactory级别,通过同一个SqlSessionFactory创建的SqlSession查询的结果会被缓存;此后若再次执行相同的查询语句,结果就会从缓存中获取
二级缓存开启的条件:
a>在核心配置文件中,设置全局配置属性cacheEnabled=“true”,默认为true,不需要设置
b>在映射文件中设置标签< cache/>
c>二级缓存必须在SqlSession关闭或提交之后有效
d>查询的数据所转换的实体类类型必须实现序列化的接口
使二级缓存失效的情况:
两次查询之间执行了任意的增删改,会使一级和二级缓存同时失效
在mapper配置文件中添加的cache标签可以设置一些属性:
①eviction属性:缓存回收策略,默认的是 LRU。
LRU(Least Recently Used) – 最近最少使用的:移除最长时间不被使用的对象。
FIFO(First in First out) – 先进先出:按对象进入缓存的顺序来移除它们。
SOFT – 软引用:移除基于垃圾回收器状态和软引用规则的对象。
WEAK – 弱引用:更积极地移除基于垃圾收集器状态和弱引用规则的对象。
②flushInterval属性:刷新间隔,单位毫秒默认情况是不设置,也就是没有刷新间隔,缓存仅仅调用语句时刷新
③size属性:引用数目,正整数代表缓存最多可以存储多少个对象,太大容易导致内存溢出
④readOnly属性:只读, true/false
true:只读缓存;会给所有调用者返回缓存对象的相同实例。因此这些对象不能被修改。这提供了 很重要的性能优势。
false:读写缓存;会返回缓存对象的拷贝(通过序列化)。这会慢一些,但是安全,因此默认是
false。(如果修改的话,修改的是拷贝过的对象,不会修改原始数据)
先查询二级缓存,因为二级缓存中可能会有其他程序已经查出来的数据,可以拿来直接使用。
如果二级缓存没有命中,再查询一级缓存
如果一级缓存也没有命中,则查询数据库
SqlSession关闭之后,一级缓存中的数据会写入二级缓存(所以二级缓存中不一定包含所有一级缓存的)
第三方缓存是针对二级缓存的
org.mybatis.caches mybatis-ehcache 1.2.1
ch.qos.logback logback-classic 1.2.3
下面两个,说白了,前面那个是借口,后面那个是前面的实现类
存在SLF4J时,作为简易日志的log4j将失效,此时我们需要借助SLF4J的具体实现logback来打印日志。 创建logback的配置文件logback.xml(名字不能改)
[%d{HH:mm:ss.SSS}] [%-5level] [%thread] [%logger][%msg]%n
正向工程:先创建Java实体类,由框架负责根据实体类生成数据库表。 Hibernate是支持正向工程的。
逆向工程:先创建数据库表,由框架负责根据数据库表,反向生成如下资源:
Java实体类
Mapper接口
Mapper映射文件
①添加依赖和插件
org.mybatis mybatis 3.5.7 junit junit 4.12 test log4j log4j 1.2.17 mysql mysql-connector-java 8.0.16
org.mybatis.generator mybatis-generator-maven-plugin 1.3.0 org.mybatis.generator mybatis-generator-core 1.3.2 mysql mysql-connector-java 8.0.16
②创建MyBatis的核心配置文件
③创建逆向工程的配置文件
文件名必须是:generatorConfig.xml
④执行MBG插件的generate目标
效果:
如果逆向工程要重新生成的话,要把上一次生成的东西删除
@Test
public void testMBG(){try {InputStream is = Resources.getResourceAsStream("mybatis-config.xml");SqlSessionFactory sqlSessionFactory = newSqlSessionFactoryBuilder().build(is);SqlSession sqlSession = sqlSessionFactory.openSession(true);EmpMapper mapper = sqlSession.getMapper(EmpMapper.class);//查询所有数据//这里不用创建Example是因为没有用到条件/*List list = mapper.selectByExample(null);list.forEach(emp -> System.out.println(emp));*///根据条件查询/*EmpExample example = new EmpExample();创建一个条件对象Criteria,后面可以直接写条件example.createCriteria().andEmpNameEqualTo("张三").andAgeGreaterThanOrEqualTo(20);example.or().andDidIsNotNull();List list = mapper.selectByExample(example);list.forEach(emp -> System.out.println(emp));*///选择修改修改mapper.updateByPrimaryKeySelective(newEmp(1,"admin",22,null,"456@qq.com",3));} catch (IOException e) {e.printStackTrace();}
}
普通和选择之间的区别,如果是普通的,条件中有属性的值为null或没有设置相关的属性,那在数据表中会将相应的字段值设置为null,但是选择不会修改未设置值或值为null的字段。
SQL语句中实现分页:
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 8,4
以最后的语句为例,此时pageNum是6,说明当前页是6,前面一共有5页,又因为pageSize是4,说明前面的5页一共有20条数据,但是第一条数据的索引是0,所以当前的第6页的第一条数据的索引是20.
①添加依赖
com.github.pagehelper pagehelper 5.2.0
②配置分页插件
在MyBatis的核心配置文件中配置插件
@Test
public void testPage() {SqlSession sqlSession = SqlSessionUtil.getSqlSession();DynamicMapperSQLMapper mapper = sqlSession.getMapper(DynamicMapperSQLMapper.class);// 查询功能之前开启分页, 第1页, 每页显示4条, 并且获取部分分页的信息// Page{count=true, pageNum=2, pageSize=4, startRow=4, endRow=8, total=0, pages=0, reasonable=null, pageSizeZero=null}[]Page
a>在查询功能之前使用PageHelper.startPage(int pageNum, int pageSize)开启分页功能
pageNum:当前页的页码
pageSize:每页显示的条数
b>在查询获取list集合之后,使用PageInfo pageInfo = new PageInfo<>(List list, int
navigatePages)获取分页相关数据
list:分页之后的数据
navigatePages:导航分页的页码数
比如在例子中navigatePages设置的值为5,说明下方的导航页的起始页码是当前页-2,末尾页码是当前页+2
c>分页相关数据
PageInfo{
pageNum=8, pageSize=4, size=2, startRow=29, endRow=30, total=30, pages=8,
//PageInfo中其实也有Page对象
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]