Mybatias
Mybatis
1.简介
1丶什么是Mybaties
-
MyBatis 是一款优秀的持久层框架,
-
它支持自定义 SQL、存储过程以及高级映射。
-
MyBatis 免除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作。
-
MyBatis 可以通过简单的 XML 或注解来配置和映射原始类型、接口和 Java POJO(Plain Old Java Objects,普通老式 Java 对象)为数据库中的记录。
如何获得Mybaties?
-
Maven仓库
<dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>x.x.x</version> </dependency>
中文文档: mybatis – MyBatis 3 | 简介
2丶持久化
数据持久化
- 持久化就是将程序的数据在持久状态和瞬时状态转化的过程
- 内存:断电即失
- 数据库(JDBC),io文件都是持久化
3丶为什么需要mybaties
- 简单
- 传统的JDBC代码太过复杂。实现了简化,框架,自动化
- 优点:
- 简单易学
- 灵活
- sql和代码的分离,提高了可维护性
- 提供映射标签,支持对象和数据库的orm字段关系映射
- 提供对象关系映射标签,支持对象关系组建维护
- 提供xml标签,支持编写动态sql
最重要一点:用的人多
2.第一个mybaties程序:
思路:搭建环境==》导入mybaties ==》编写代码 ==》测试
1丶开发环境
CREATE DATABASE mybaties;
USE mybaties;
CREATE TABLE `user`(
id INT NOT NULL,
`name` VARCHAR(20) NOT NULL,
`pwd` VARCHAR(30) NOT NULL,
PRIMARY KEY (id)
)
INSERT INTO `user` VALUE(1,'六的很','123'),(2,'lc','1234'),(3,'zyj','075');
SELECT * FROM `user`
创建父项目
-
创建一个普通的maven项目
-
删除src(因为我们不用,这个是父模块,只是用来导依赖的)
-
导入依赖(mybatis,mysql,junit)
-
设置打包方式为:jar
<dependencies> <!-- mybatis --> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.5.7</version> </dependency> <!-- mysql--> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.3</version> </dependency> <!-- junit --> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> <scope>test</scope> </dependency> </dependencies>
2丶编写mytabis的核心配置文件
<?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>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver"/>
"jdbc:mysql://localhost:3306/mybaties?characterEncoding=utf-8&serverTimezone=UTC&useSSL=false">
<property name="username" value="root"/>
<property name="password" value="123"/>
</dataSource>
</environment>
</environments>
//引入映射文件
<mappers>
<mapper resource="org/mybatis/example/BlogMapper.xml"/>
</mappers>
</configuration>
3丶编写mapper接口
Mybatis面向接口编程的两个一致:(重)
- 映射文件的namespace要和mapper接口的全类名保持一致
- 映射文件中SQL语句的id要和mapper接口的方法名一致
相当于原来的Dao
public interface UserDao {
// 查询
List<User> getUserList();
User getUserName(int id);
}
4丶编写mapper映射文件
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--命名空间绑定一个DAO/mapper接口-->
<mapper namespace="com.LiuDeHen.mapper.Usermapper">
</mapper>
5丶引入映射文件
//引入映射文件
<mappers>
<mapper resource="org/mybatis/example/BlogMapper.xml"/>
</mappers>
6丶使用junit测试
@Test
public void test() throws IOException {
// 记载核心配置文件
InputStream resource = Resources.getResourceAsStream("mybatis-config.xml");
// 获取sqlsessionFactoryBuilder
SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
// 获取sqlsessionFactory
SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(resource);
// 获取sqlsession,参数为true就是设置为自动提交事务,一个sqlsession对象就表示和数据库的一次会话
SqlSession sqlSession = sqlSessionFactory.openSession(true);
// 获取mapper接口对象
// 将一个接口丢进去获得一个实例化对象,底层是帮我们实现了接口的实现类,是代理模式
userMapper mapper = sqlSession.getMapper(userMapper.class);
// 测试功能
int i = mapper.insertUser();
if (i>0){
System.out.println("插入成功");
}
// 提交事务
sqlSession.commit();
}
7丶加入log4j日志功能
什么是LOG4J?
-
我们也可以控制每一条日志的输出格式
-
通过定义每一条日志信息的级别,我们能够更加细致地控制日志的生成过程
-
这些可以通过一个配置文件来灵活地进行配置,而不需要修改应用的代码
-
添加依赖
<dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>1.2.17</version> </dependency>
-
添加log4j配置文件[properties]
#将等级为DEBUG的日志信息输出到console和file这两个目的地,console和file的定义在下面的代码 log4j.rootLogger=DEBUG,console,file #控制台输出的相关设置 log4j.appender.console = org.apache.log4j.ConsoleAppender log4j.appender.console.Target = System.out log4j.appender.console.Threshold=DEBUG log4j.appender.console.layout = org.apache.log4j.PatternLayout log4j.appender.console.layout.ConversionPattern=[%c]-%m%n #文件输出的相关设置 log4j.appender.file = org.apache.log4j.RollingFileAppender log4j.appender.file.File=./log/kuang.log log4j.appender.file.MaxFileSize=10mb log4j.appender.file.Threshold=DEBUG log4j.appender.file.layout=org.apache.log4j.PatternLayout log4j.appender.file.layout.ConversionPattern=[%p][%d{yy-MM-dd][%c]%m%n #日志输出级别 log4j.logger.org.mybatis=DEBUG log4j.logger.java.sql=DEBUG log4j.logger.java.sql.Statement=DEBUG log4j.logger.java.sql.ResultSet=DEBUG log4j.logger.java.sql.PreparedStatement=DEBUG
8丶封装工具类SqlSessionUtils
public class SqlSessionUtils {
public static SqlSession getSqlsession(){
SqlSession sqlSession=null;
try {
InputStream resourceAsStream = Resources.getResourceAsStream("mybatis-config.xml");
SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
SqlSessionFactory build = sqlSessionFactoryBuilder.build(resourceAsStream);
sqlSession = build.openSession(true);
} catch (IOException e) {
e.printStackTrace();
}
return sqlSession;
}
}
9丶设置核心配置和映射文件模板
10丶测试增删查改
查询功能的标签必须设置 resultType或者resultMap
resultType:设置默认的映射关系(当查询返回来的字段与映射的实体类的属性一致,就赋值)
resultMap:设置自定义的映射关系(属性不一致)
-
mapper接口
public interface userMapper { int insertUser(); void updateUser(); void deleteuser(); user selectID(); List<user> selectAll(); }
-
mapper.xml
<!--插入--> <insert id="insertUser" parameterType="com.LiuDeHen.pojo.user"> insert into mybaties.user values (21,'lc','123'); </insert> <!-- void updateUser();--> <update id="updateUser"> update mybaties.user set name='liuchao' where id=21 </update> <!-- void deleteuser();--> <delete id="deleteuser"> delete from mybaties.user where id=1; </delete> <!-- user selectID();--> <!-- 查询功能的标签必须设置 resultType或者resultMap resultType:设置默认的映射关系(当查询返回来的字段与映射的实体类的属性一致,就赋值) resultMap:设置自定义的映射关系(属性不一致) --> <select id="selectID" resultType="com.LiuDeHen.pojo.user" > select * from mybaties.user where id=2 </select> <!-- List<user> selectAll();--> <select id="selectAll" resultType="com.LiuDeHen.pojo.user"> select * from mybaties.user; </select>
-
test测试
@Test
public void ces() throws IOException {
InputStream resourceAsStream = Resources.getResourceAsStream("mybatis-config.xml");
SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
SqlSessionFactory build = sqlSessionFactoryBuilder.build(resourceAsStream);
SqlSession sqlSession = build.openSession(true);
userMapper mapper = sqlSession.getMapper(userMapper.class);
// 以id查询
user user = mapper.selectID();
System.out.println(user);
// 查询全部
List<user> users = mapper.selectAll();
ListIterator<user> iterator = users.listIterator();
while (iterator.hasNext()){
user next = iterator.next();
System.out.println(next);
}
// 删除
mapper.deleteuser();
// 添加
mapper.insertUser();
// 修改
mapper.updateUser();
}
11丶总结:
一下流程:
-
首先第一步,就是环境的配置
- mysql和mybatis的jar包
- 然后写mybatis的xml文件(不要忘了注册),mapper是驱动,也就是我们写的每一个mapper(就是我们原来的操作数据库类,现在是mapper.xml文件),并且绑定上mysql驱动,和我们的数据库(连接数据库)
- 到了这里,我们要去编写工具类,根据官方文档。工具类里会根据我们前面的mybatis.xml文件得到一个sqlSessionFactory工厂,使用这个工厂我们可以获取到SqlSession对象(操作sql所有的方法)
- 然后我们就需要去写实体类,与数据库要对应
- 接下来再写上Dao层的接口和mapper.xml文件(代替原来的Dao实现类),mapper文件绑定id到接口的方法,返回值类型为实体类
-
测试
-
后面的所有操作都只需要写mapper.xml里的sql语句了,实现了和java代码的解耦,提高维护性
-
项目结构
我们需要了解的三个接口和类
3.配置解析:
1丶配置如下
- configuration(配置)
- properties(属性)
- settings(设置)
- typeAliases(类型别名)
- typeHandlers(类型处理器)
- objectFactory(对象工厂)
- plugins(插件)
- environments(环境配置)
- environment(环境变量)
- transactionManager(事务管理器)
- dataSource(数据源)
- databaseIdProvider(数据库厂商标识)
- mappers(映射器)
2丶环境配置(environments)
<environments default="development">
//default: mybatis可以配置多个environment ,但是一个项目只能用一种,default设置默认的是哪一种
<environment id="development">
//type="JDBC/MANAGED" jdbc:使用原生jdbc的事务管理方式 MANAGED:被管理,例如Spring
<transactionManager type="JDBC"/>
//datasource:配置数据源
//type:设置数据源的类型 type="POOLED\UNPOOLED\JNDI"
//POOLED:使用数据库连接池缓存数据库连接
//UNPOOLED:不使用数据库连接池缓存
//JNDI:表示使用上下文中的数据源
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/mybaties?serverTimezone=UTC"/><!--数据库连接-->
<property name="username" value="root"/>
<property name="password" value="123"/>
</dataSource>
</environment>
</environments>
-
mybatis可以适应多种环境
-
但每个SqlSessionFactory实例只能选择一种实例
-
学会配置多套运行环境,但是一个项目只能运行一个
-
mybatis默认事务管理器是jdbc,
-
dataSource 使用 JDBC 数据源连接对象的资源。 含池的数据源类型:POOLED
3丶属性([properties)
-
配置文件要按照顺序
-
mybatis.properties
//防止重名,可以加个jdbc.的前缀 jdbc.driver=com.mysql.jdbc.Driver jdbc.url=jdbc:mysql://localhost:3306/mybaties?useSSL=false&;characterEncoding=UTF-8&;useUnicode=true&;serverTimezone=GMT jdbc.username=root jdbc.password=123
-
核心配置文件中声明properties并引入外部地址
<properties resource="mybatis.properties"/>
-
使用外部配置文件
<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>
4丶类型别名(typeAliases)
类型别名可为 Java 类型设置一个缩写名字。 它仅用于 XML 配置,意在降低冗余的全限定类名书写。
-
同样要注意标签顺序
properties?, settings?, typeAliases?, typeHandlers?, objectFactory?,objectWrapperFactory?, reflectorFactory?, plugins?, environments?, databaseIdProvider?, mappers?
-
第一种自定义别名
-
第二种,以包名下的类起别名(常用)
<typeAliases>
<!-- 自定义
type:设置需要别名的类型的全类名
alias:设置某个类的别名
别名不区分大小写,如果不写alias就以我们的类名为别名
-->
<typeAlias type="com.LiuDeHen.pojo.User" alias="User"/>
<!-- 以类名
以包下的每个类的类名为别名,也不区分大小写
-->
<package name="com.LiuDeHen.pojo"/>
</typeAliases>
-
第三种就是注解了
@Alias("author") public class Author { ... }
在实体类少的情况下可以用自定义,多就用第二种
5丶设置
- cacheEnabled 缓存
- mapUnderscoreToCamelCase 将sql里 字段 index_name 转化为驼峰 indexName
6丶其他配置
7丶映射器(mappers)
在resource下创建包的时候,比如com.LiuDeHen.mapper.xml,这只会是一层目录
要想创建一层一层的包,必须这么创建 com/LiuDeHen/mapper/xml
MapperRegistry:注册绑定我们的Mapper文件
-
第一种:使用扫描包进行绑定注册包下所有文件
<mappers> <package name="com.LiuDeHen.Dao"/> </mappers>
注意点:
- 接口和Mapper映射文件必须同名
- 接口和Mapper映射文件必须在同一个包下
- 像上图这样,在同一个包下
-
第二种:resource (推荐使用)进行绑定
<mappers> <mapper resource="com/LiuDeHen/Dao/UserMapper.xml"/> </mappers>
-
第三种:class进行绑定
<mappers> <mapper class="com.LiuDeHen.Dao.UserMapper"/> </mappers>
注意点:
- 接口和Mapper配置文件必须同名
- 接口和Mapper配置文件必须在同一个包下
技巧:
如果想将Dao下的Mapper文件放到resource下,在resources下建一个和接口所在相同的包,使用 resource 的方式,路径不加resources,对比老师的来如
8丶生命周期和作用域
生命周期和作用域,是至关重要的,因为错误的使用回导致非常严重的并发问题
SqlSessionFactoryBuilder:
- 一旦创建了 SqlSessionFactory,就不再需要它了
- 佳作用域是方法作用域(也就是局部方法变量)
SqlSessionFactory:
- 说白了可以把它当成:数据库连接池
- SqlSessionFactory 一旦被创建就应该在应用的运行期间一直存在,没有任何理由丢弃它或重新创建另一个实例
- 最佳作用域是应用作用域
- 使用单例模式或者静态单例模式
SqlSession:
- 连接到连接池的一个请求
- 用完需要关闭,释放池中资源
- SqlSession 的实例不是线程安全的,因此是不能被共享的,所以它的最佳的作用域是请求或方法作用域
4.Mybatis获取参数值的两种方式(重点)
- ${}:本质是jdbc的字符拼接
{}本质是jdbc的占位符赋值
- 记住当需要传入值的名字的时候,形参只是数据,我们最好用@Param注解,标识一个名字,用来调用
1丶mapper接口的方法参数为单个字面量类型
- 两个都可以获取,且名称任意
<!-- user selectname(String name);-->
<select id="selectname" resultType="user">
select * from mybaties.user where name=#{user}; <!--这里的占位符,只是占一个位置,不代表参数名,所以名字任意 -->
select *from mybaties.user where name='${user}' <!-- 跟字符串拼接一样需要单引号,同样是任意名称-->
</select>
2丶mapper接口方法的参数为多个时
-
此时mybatis会将这些参数放在一个map集合中,以两种方式进行储存
-
以arg0,arg1为键,以参数为值
-
以param1,param2为键,以参数为值
<!-- user checkLogin(String name,String pwd);--> <select id="checkLogin" resultType="user"> select * from mybaties.user where name=#{arg0} and pwd=#{arg1}; select * from mybaties.user where name=#{param1} and pwd=#{param2}; select * from mybaties.user where name='${param1}' and pwd='${param2}'; select * from mybaties.user where name='${arg0}' and pwd='${param2}'; </select>
3丶mapper接口方法的参数为多个时,我们使用自己创建的Map
-
此时name和pwd就是我们自己定义的键
Map<String, Object> map = new HashMap<>(); map.put("name","liuchao"); map.put("pwd","123");
<!-- user checkLogin2(Map<String,Object> map);-->
<select id="checkLogin2" resultType="user">
select * from mybaties.user where name=#{name} and pwd=#{pwd};
</select>
4丶mapper接口方法的参数为对象时(常用)
-
我们知道Map集合会根据传来的Map通过键来找值,那对象同样,是通过属性访问属性值
-
所以一定要跟对象属性名对应
<!-- int insertUser2(user u);--> <insert id="insertUser2"> insert into mybaties.user values (#{id},#{name},#{pwd}) </insert>
5丶使用@Param注解命名参数(常用)
- 第二种方法中,我们的参数会被放到系统的Map里,但是必须使用默认键
- 第三种方法中,我们使用自定义的Map集合,使用自己定义的Map键
- 那么@Param注解就是综合两种方法,它会把我们的值放到系统Map里,并使用我们自己定义的键
<!--user checkLogin3(@Param("name") String name,@Param("pwd") String pwd);-->
<select id="checkLogin3" resultType="user">
select * from mybaties.user where name=#{name} and pwd=#{pwd}
</select>
- @Param源码分析
5.各种查询
1丶查询一条数据时,
-
可以用对象接收
-
list集合接收
-
也可以用Map集合接收
{name=zz, id=5, pwd=123}
2丶查询多条数据时
-
用实体类类型的list集合接收
-
用Map类型的list集合接收
-
Mybatis为我们设置了默认的类型别名(可以用来查单行单列)
<!--int selectAll2();--> <select id="selectAll2" resultType="java.lang.Integer"> select COUNT(*) from mybaties.user </select>
-
下面这些都是对应的
-
3丶当查询返回为map集合时
-
查询一条
<!-- Map<String,Object> selectAll3(@Param("id")Integer id);;--> <select id="selectAll3" resultType="map"> select * from mybaties.user where id=#{id} </select>
-
查询多条:
- 第一种
- 要使用@MapKey这个注解,因为返回的Map只能是一条
- 使用这个注解,会以注解的value值作为键,把原来的Map作为值,形成一个二位Map输出
- 第二种
- 用Map类型的list集合接收
<!-- @MapKey("name") Map<String,Object> selectAll4(); List<Map<String,Object>> selectAll5(); --> <select id="selectAll4" resultType="map"> select * from mybaties.user </select>
- 第一种
6.特殊的SQL执行
1丶模糊查询
-
第一种
-
使用$,不能使用#,因为会被当成是占位符?拼接到字符串里
<!-- List<Object> selectName(@Param("name") String name); --> <select id="selectName" resultType="user"> select * from mybaties.user where name like '${name}%' </select>
-
-
第二种
-
使用concat拼接字符串
select * from mybaties.user where name like concat('%',#{name},'%');
-
-
第三种
select * from mybaties.user where name like '%'#{name}'%'
2丶批量删除
只能用$,因为#占位符接收参数会自动加上单引号 ,而批量删除in()里不能有引号
<!-- int deleteMore(@Param("id") String id);-->
<delete id="deleteMore">
delete from mybaties.user where id in(${id})
</delete>
3丶动态设置表名
同样,只能用$
<!-- List<user> selectMove(@Param("tablename")String tablename); -->
<select id="selectMove" resultType="user">
select * from ${tablename}
</select>
4丶添加功能获取自增的主键
class(class_id,class_name)
student(student_id,student_name,class_id)
- 可以将有自增主键的的表的主键值
- 因为原本是自添加,所以我们不要插入id值,自己会有,但是我们插入后,在测试类里是查不到id的
- 所以可以用这两个属性,设置为后,可以查到id
- 就可以将这个class_id给另一个表使用
<!-- int insertUser(User2 user2);
useGenerratedkey:设置当前标签中使用了自增主键,
keyProperty:将自增的主键的值 赋给传输映射文件中参数的的某个属性
-->
<insert id="insertUser" useGeneratedKeys="true" keyProperty="id">
insert into mybaties.user2 values (null,#{name},#{pwd})
</insert>
7.自定义映射resultMap
使用的数据库
create table t_emp(
eid int PRIMARY KEY AUTO_INCREMENT not null ,
emp_name varchar(20),
age int,
sex char,
email varchar(20),
did int
);
create table t_dept(
did int PRIMARY KEY AUTO_INCREMENT not null ,
dept_name varchar(20)
);
insert into t_emp values (null,'四四',21,'女','21222@qq.com',1);
insert into t_dept values (null,'C');
实体类
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Emp {
private int eid;
private String empName;
private Integer age;
private String sex;
private String email;
private Dept dept;
多对一里,有对象
}
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Dept {
private int did;
private String deptname;
private List<Emp> list;
一对多里,有集合
}
解决字段名和属性名不一致的问题
1丶为字段起别名,保持和属性名 一致
<!-- List<Emp> selectAll();-->
<select id="selectAll" resultType="Emp">
//empname是属性名
select eid, emp_name as empname, age, sex, email from mybaties.t_emp
</select>
2丶mapUnderscoreToCamelCase 设置全局配置,将自动映射为驼峰
<settings>
<setting name="mapUnderscoreToCamelCase" value="true"/>
</settings>
3丶使用resultMap
- resultMap设置自定义映射关系
- id唯一标识,不能重复
- type:映射关系中的实体类类型
- id标签设置主键的映射关系
- result表示普通属性的映射关系
- property设置映射关系中的属性名,必须是type属性所设置的实体类中的属性名
- column设置映射关系中的字段名,必须是sql语句查询出来的字段 名
<resultMap id="empResultmap" type="emp"> //id就是被调用的名字,type就是映射的实体类
<id property="id" column="id"/> //主键映射
<result property="empName" column="emp_name"/>///:普通属性映射
<result property="age" column="age"/> //property实体类的属性,column数据库查询出来的字段
<result property="sex" column="sex"/>
<result property="email" column="email"/>
</resultMap>
<!-- List<Emp> selectAll();-->
<select id="selectAll" resultMap="empResultmap"> //**调用自己定义的resultMap**
<!--select eid, emp_name as empname, age, sex, email from mybaties.t_emp-->
select * from mybaties.t_emp
</select>
4丶多对一处理
多对一:对应对象
这个案例里就是多个员工对应一个部门
第一种:级联属性赋值
<resultMap id="EmpAndDeptResulymap" type="Emp">
<id property="eid" column="eid"/>
<result property="empName" column="emp_name"/>
<result property="age" column="age"/>
<result property="sex" column="sex"/>
<result property="email" column="email"/>
//dept.did的对象.属性, 将联表查询的did赋值过去
<result property="dept.did" column="did"/>
<result property="dept.deptname" column="dept_name"/>
</resultMap>
<!-- Emp EmpselectDept(@Param("eid") String eid); -->
<select id="EmpselectDept" resultMap="EmpAndDeptResulymap">
select * from mybaties.t_emp,mybaties.t_dept
where mybaties.t_dept.did=t_emp.did and eid=#{eid}
</select>
第二种:association标签
- association:处理多对一的映射关系
- javaType:就是属性里多对一的那个一的类型
- 此时标签里的属性
- property表示javaType的那个类的属性
- column:同样是sql查出来的字段
- javaType:就是属性里多对一的那个一的类型
<resultMap id="EmpAndDeptResulymapTwo" type="Emp">
<id property="eid" column="eid"/>
<result property="empName" column="emp_name"/>
<result property="age" column="age"/>
<result property="sex" column="sex"/>
<result property="email" column="email"/>
<association property="dept" javaType="Dept">
<id property="did" column="did"/>
<result property="deptname" column="dept_name"/>
</association>
</resultMap>
<!-- Emp EmpselectDept(@Param("eid") String eid); -->
<select id="EmpselectDept" resultMap="EmpAndDeptResulymapTwo">
select * from mybaties.t_emp,mybaties.t_dept
where mybaties.t_dept.did=t_emp.did and eid=#{eid}
</select>
第三种:分布查询
-
分布查询
-
在这个案例里我们多对一,要查询另一个表t_Dept的数据
-
首先,我们可以先查第一个表t_emp的数据
-
我们要知道第一个表的实体类,有第二个表的实体类对象,所以肯定要使用resultMap
-
此时的association的属性介绍
- property还是type=Emp类的属性
- select:设置分布查询的唯一标识,是我们另一个表的查询方法的地址(mapper接口全类名.方法名)
- column:分布查询的条件
<resultMap id="EmpAndDeptResulymapThree" type="Emp"> <id property="eid" column="eid"/> <result property="empName" column="emp_name"/> <result property="age" column="age"/> <result property="sex" column="sex"/> <result property="email" column="email"/> <association property="dept" select="com.LiuDeHen.mapper.DeptMapper.DeptSelect" column="did" > </association> </resultMap> <!-- Emp empSelect(@Param("eid") Integer eid); --> <select id="empSelect" resultMap="EmpAndDeptResulymapThree"> select * from mybaties.t_emp where eid=#{eid} </select>
-
-
再查第二个表的数据
-
-
<!-- Dept DeptSelect(@Param("did") Integer did); -->
<select id="DeptSelect" resultType="Dept">
select * from mybaties.t_dept where did=#{did}
</select>
延迟加载
分步查询的优点:可以实现延迟加载,但是必须在核心配置文件中设置全局配置信息:lazyLoadingEnabled:延迟加载的全局开关。当开启时,所有关联对象都会延迟加载
我的版本3.5.7默认为true,所以也可以不用设置
aggressiveLazyLoading:当开启时,任何方法的调用都会加载该对象的所有属性。否则,每个属性加载(3.4版本后,默认为false,所以不需要我们自己设置为false)
此时就可以实现按需加载,获取的数据是什么,就只会执行相应的sql。此时可通过association和collection中的fetchType属性设置当前的分步查询是否使用延迟加载,fetchType="lazy(延迟加载)|eager(立即加载)"
效果
比如我们在查询,两个表其中的一个表中数据的时候(不需要另一个表辅助)
@Test
public void DeptselectEmptest(){
SqlSession sqlsession = SqlSessionUtils.getSqlsession();
EmpMapper mapper = sqlsession.getMapper(EmpMapper.class);
Emp emp = mapper.empSelect(2);
System.out.println(emp.getSex());
}
开启延迟加载的
没开启的
怎么开启
- 确保lazyLoadingEnabled为ture
- 确保aggressiveLazyLoading为false
- 并且设置 fetchType="lazy"
<association property="dept"
select="com.LiuDeHen.mapper.DeptMapper.DeptSelect"
column="did"
fetchType="lazy"
>
</association>
5丶一对多处理
- 第一种collection处理
- 标签collection是集合,专门用来处理一对多
- ofType:表示集合里的数据的类型
- 标签collection是集合,专门用来处理一对多
<resultMap id="deptAndEmpResultMap" type="Dept">
<id property="did" column="did"/>
<result property="deptname" column="dept_name"/>
<collection property="list" ofType="Emp">
<id property="eid" column="eid"/>
<result property="empName" column="emp_name"/>
<result property="age" column="age"/>
<result property="sex" column="sex"/>
<result property="email" column="email"/>
</collection>
</resultMap>
<!-- Dept deptAndEmp(@Param("did") Integer did);-->
<select id="deptAndEmp" resultMap="deptAndEmpResultMap">
select * from mybaties.t_dept,mybaties.t_emp
where mybaties.t_dept.did=mybaties.t_emp.did and mybaties.t_dept.did=#{did}
</select>
-
第二种:分布查询
- 先查部门表
- 根据部门did再去查员工表
- 延迟加载跟多对一一样
- 多对一和一对多里column条件是一样的,都是联表查询的公共字段
<resultMap id="deptAndEmpAllResultMap" type="Dept"> <id property="did" column="did"/> <result property="deptname" column="dept_name"/> <collection property="list" select="com.LiuDeHen.mapper.EmpMapper.EmpAndDeptAll" column="did" fetchType="lazy" /> </resultMap> <!-- Dept deptAndEmpAll(@Param("did") Integer did);--> <select id="deptAndEmpAll" resultMap="deptAndEmpAllResultMap"> select * from mybaties.t_dept where did=#{did} </select>
<!-- List<Emp> EmpAndDeptAll(@Param("did") Integer did);--> <select id="EmpAndDeptAll" resultType="Emp"> select * from mybaties.t_emp where did=#{did} </select>
8.动态sql
什么是动态sql? 根据不同的条件生成不同的sql语句
Mybatis框架的动态SQL技术是一种根据特定条件动态拼装SQL语句的功能,它存在的意义是为了解决拼接SQL语句字符串时的痛点问题。
如果你之前用过 JSTL 或任何基于类 XML 语言的文本处理器,你对动态 SQL 元素可能会感觉似曾相识。在 MyBatis 之前的版本中,需要花时间了解大量的元素。借助功能强大的基于 OGNL 的表达式,MyBatis 3 替换了之前的大部分元素,大大精简了元素种类,现在要学习的元素种类比原来的一半还要少。
if
where
choose (when, otherwise)
trim (where, set)
foreach
sql
1丶if标签
if :根据标签中test属性所对应的表达式决定标签中的内容是否需要拼接到sQL中
- 使用标签if
- 属性test为判断条件
- 里面的判断内容是用的实体类属性判断,因为是传参是实体类
- 标签里的内容为 拼接内容
- 内容格式语法为:字段名=#{属性名}
- where 1=1 为恒成立条件,当"empName!=null and empName!=''"不成立的时候,直接回去拼接后面age等的,age等前有and拼接关键字,当第一个if不满足就会出现
- 属性test为判断条件
where后面直接接了and
加了恒等条件后,就不会出现问题
<!-- List<Emp> getdynamicSQL(Emp emp);-->
<select id="getdynamicSQL" resultType="Emp">
select * from mybaties.t_emp where 1=1
<if test="empName!=null and empName!=''">
emp_name=#{empName}
</if>
<if test="age!=null and age!=''">
and age=#{age}
</if>
<if test="sex!=null and sex!=''">
and sex=#{sex}
</if>
<if test="email!=null and email!=''">
and email=#{email}
</if>
</select>
2丶where标签
使用where标签代替关键字
- 我们上面要用到where 1=1 恒成立等式,避免拼接到and
- 当有条件成立时,会自动生成where关键字,能帮我们自动去掉前面的and或者or,但是不能省去后的and或者or
- 当我们所有的条件都不成立时,会帮我们自动去掉where
<!-- List<Emp> getdynamicSQL(Emp emp);-->
<select id="getdynamicSQL" resultType="Emp">
select * from mybaties.t_emp
<where>
<if test="empName!=null and empName!=''">
emp_name=#{empName} <!--and/or 放在后面不能自动去掉-->
</if>
<if test="age!=null and age!=''">
or age=#{age}
</if>
<if test="sex!=null and sex!=''">
and sex=#{sex}
</if>
<if test="email!=null and email!=''">
and email=#{email}
</if>
</where>
</select>
3丶trim标签
- trim
- prefix="" suffix="" :在trim标签内容 前后添加指定内容
- prefixOverrides="" suffixOverrides="" : 在trim标签中内容前后去掉指定内容
- 像where一样,如果trim标签的内容都不成立,trim就不会生效
- 它可以做到去掉后面的and或者or
<!-- List<Emp> getdynamicSQL(Emp emp);-->
<select id="getdynamicSQL" resultType="Emp">
select * from mybaties.t_emp
<trim suffix="" prefix="where" suffixOverrides="and|or" prefixOverrides="">
<if test="empName!=null and empName!=''">
emp_name=#{empName} and
</if>
<if test="age!=null and age!=''">
age=#{age} or
</if>
<if test="sex!=null and sex!=''">
sex=#{sex} and
</if>
<if test="email!=null and email!=''">
email=#{email} and
</if>
</trim>
</select>
4丶choose when otherwise
- 相当于java的switch case default
- when最少有一个,otherwise最多有一个
<!-- List<Emp> getdynamicSQL(Emp emp);-->
<select id="getdynamicSQL" resultType="Emp">
select * from mybaties.t_emp
where
<choose>
<when test="empName!=null and empName!=''">
emp_name=#{empName}
</when>
<when test="age !=null and age!=''">
age=#{age}
</when>
<when test="sex !=null and sex!=''">
sex=#{sex}
</when>
<when test="email !=null and email!=''">
email=#{email}
</when>
<otherwise>
did=1
</otherwise>
</choose>
</select>
5.foreach
实现批量删除
- foreach标签
- collection:遍历的是哪一个集合/数组
- item:遍历的数组/集合中的每一个数据
- open:foreach标签所循环的所有内容的开始符
- close:foreach标签所循环的所有内容的结束符
- separator:每一个数据中间用什么隔开
第一种使用 in
<!-- int deleteMoreSQL(@Param("eids") Integer []eid);-->
<delete id="deleteMoreSQL">
delete from mybaties.t_emp where eid in
<foreach collection="eids" item="e" open="(" close=")" separator=",">
#{e}
</foreach>
</delete>
第二种使用or
<!-- int deleteMoreSQL(@Param("eids") Integer []eid);-->
<delete id="deleteMoreSQL">
delete from mybaties.t_emp where eid=
<foreach collection="eids" item="e" separator="or">
#{e}
</foreach>
</delete>
sql拼接效果:
delete from mybaties.t_emp where eid in ( ? , ? , ? )
delete from mybaties.t_emp where eid= ? or ? or ?
实现批量添加
<!-- int insertMoreSQL(@Param("emps") List<Emp> emps);-->
<insert id="insertMoreSQL">
insert into mybaties.t_emp values
<foreach collection="emps" item="emp" separator=",">
(null,#{emp.empName},#{emp.age},#{emp.sex},#{emp.email},null)
</foreach>
</insert>
sql拼接效果:
insert into mybaties.t_emp values (null,?,?,?,?,null) , (null,?,?,?,?,null) , (null,?,?,?,?,null)
6丶SQL片段
设置sql片段 :
<sql id="empSQL">eid,emp_name,age, sex, email</sql>
引用片段 :
select <include refid="empSQL"></include> from mybaties.t_emp
9.分页查询
为什么需要分页?
- 减少数据的处理量
使用limit分页
select * from 表名 limit indexstart rows indexstart:起始行数 rows:多少行
使用mybatis实现分页
-
接口
// 分页查询 List<User> getLimit(Map<String,Object> map);
-
mapper文件
对应的resultMap解决字段和属性不一样 <resultMap id="UserMap" type="User"> <!-- column对应着数据库的字段,property对应着实体类的属性 --> <result column="pwd" property="password"/> </resultMap> <select id="getLimit" resultMap="UserMap" parameterType="map"> select * from mybaties.user limit #{start},#{rows}; </select>
-
测试
@Test public void testLimit(){ SqlSession sqlSession = MybatisUtils.getsqlSession(); UserMapper mapper = sqlSession.getMapper(UserMapper.class); HashMap<String, Object> hashMap = new HashMap<String, Object>(); hashMap.put("start",0); hashMap.put("rows",3); List<User> limit = mapper.getLimit(hashMap); for (User user : limit) { System.out.println(user); } sqlSession.close(); }
10.使用注解开发
-
在接口中使用注解
@Select("select id,name,pwd as password from mybaties.User") List<User> getUser();
-
在核心配置文件中绑定接口
<mappers> <mapper class="com.LiuDeHen.Dao.UserMapper"/> </mappers>
-
测试
@Test public void test() { SqlSession sqlSession = MybatisUtils.getsqlSession(); UserMapper mapper = sqlSession.getMapper(UserMapper.class); List<User> user = mapper.getUser(); for (User user1 : user) { System.out.println(user1); } sqlSession.close(); }
本质:反射机制
底层:动态代理
9.mybaitis流程基本梳理
-
首先我们在使用时,会调用工具类MybatisUtils
-
里面有一个resource路径是我们的全局核心配置文件
-
然后会获取一个流,并将这个流传给build方法
-
这个build方法里有个构造器XMLConfigBuilder(),它会将流里(核心配置文件里)的环境等传进去,返回得到一个sqlSessionFactory工厂
-
通过工厂获取SqlSession实现crud操作sql
-
SqlSession可以通过getMapper方法再使用反射动态获取是哪一个接口
-
11.使用注解实现增删查改
//使用注解增删改查
public interface UserMapper {
@Select("select id,name,pwd as password from mybaties.User")
List<User> getUser();
@Select("select * from mybaties.User where id=#{id}")
User getUserID(@Param("id") int id);
@Insert("insert into mybaties.user values(#{id},#{name},#{pwd})")
int getInsert(User user);
@Update("update mybaties.User set name=#{name} where id=#{id}")
int getUpdate(User user);
@Delete("delete from mybaties.User where id=#{id}")
int getDelete(@Param("id") int id);
//测试:
public void test() {
SqlSession sqlSession = MybatisUtils.getsqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
List<User> user = mapper.getUser();
for (User user1 : user) {
System.out.println(user1);
}
sqlSession.close();
}
@Test
public void testId(){
SqlSession sqlSession = MybatisUtils.getsqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
User user = mapper.getUserID(1);
System.out.println(user);
sqlSession.close();
}
@Test
public void testInsert(){
SqlSession sqlSession = MybatisUtils.getsqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
int zz = mapper.getInsert(new User(6, "zz", "222"));
if (zz>0){
System.out.println("插入成功");
}
sqlSession.close();
}
@Test
public void testUpdate(){
SqlSession sqlSession = MybatisUtils.getsqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
int zz = mapper.getUpdate(new User(6, "lc",""));
if (zz>0){
System.out.println("修改成功");
}
sqlSession.close();
}
@Test
public void testDelet(){
SqlSession sqlSession = MybatisUtils.getsqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
int zz = mapper.getDelete(3);
if (zz>0){
System.out.println("删除成功");
}
sqlSession.close();
}
注意在使用工厂回去sqlsession时,将option设置成true,就能dml事务自动提交
return sqlSessionFactory.openSession(true);
12.lombok
可以简化实体类得代码
使用步骤
-
安装插件
-
项目导入jar包
-
在实体类上加注解
@Getter and @setter @Fie1dNameConstants @Tostring @EqualsAndHashcode
13.缓存
1丶一级缓存
范围:一个sqlsssion会话
一级缓存是SqlSession级别的,通过同一个SqlSession查询的数据会被缓存,下次查询相同的数据,就会从缓存中直接获取,不会从数据库重新访问
使一级缓存失效的四种情况:
-
1)不同的SqlSession对应不同的一级缓存
-
2)同一个SqlSession但是查询条件不同
-
3)同一个SqlSession两次查询期间执行了任何一次增删改操作
-
4)同一个SqlSession两次查询期间手动清空了缓存
2丶二级缓存
范围:SqlSessionFactory创建的所有sqlsession
二级缓存是SqlSessionFactory级别,通过同一个SqlSessionFactory创建的SqlSession查询的结果会被缓存;此后若再次执行相同的查询语句,结果就会从缓存中获取
二级缓存开启的条件:
-
a>在核心配置文件中,设置全局配置属性cacheEnabled="true",默认为true,不需要设置
-
b>在映射文件中设置标签
-
c>二级缓存必须在SqlSession关闭或提交之后有效
-
d>查询的数据所转换的实体类类型必须实现序列化的接口
-
使二级缓存失效的情况:
-
两次查询之间执行了任意的增删改,会使一级和二级缓存同时失效
3丶二级缓存的配置
在mapper配置文件中添加的cache标签可以设置一些属性:.
-
eviction属性:缓存回收策略
LRU (Least Recently Used)-最近最少使用的:移除最长时间不被使用的对象。
FIFO (First in First out)-先进先出:按对象进入缓存的顺序来移除它们。
SOFT-软引用:移除基于垃圾回收器状态和软引用规则的对象。
WEAK-弱引用:更积极地移除基于垃圾收集器状态和弱引用规则的对象。
默认的是 LRU。
-
flushlnterval属性:刷新间隔,单位毫秒
默认情况是不设置,也就是没有刷新间隔,缓存仅仅调用语句时刷新
-
size属性:引用数目,正整数
代表缓存最多可以存储多少个对象,太大容易导致内存溢出. -
readOnly属性:只读,true/false
true:只读缓存;会给所有调用者返回缓存对象的相同实例。因此这些对象不能被修改。这提供了很重要的性能优势。
false:读写缓存;会返回缓存对象的拷贝(通过序列化)。这会慢一些,但是安全,因此默认是false。
4丶缓存查询的顺序
-
先查询二级缓存,因为二级缓存中可能会有其他程序已经查出来的数据,可以拿来直接使用。
-
如果二级缓存没有命中,再查询一级缓存
-
如果一级缓存也没有命中,则查询数据库
-
SqlSession关闭之后,一级缓存中的数据会写入二级缓存
14.mybatis逆向工程
-
正向工程:先创建Java实体类,由框架负责根据实体类生成数据库表。Hibernate是支持正向工程的
-
逆向工程:先创建数据库表,由框架负责根据数据库表,反向生成如下资源:
-
Java实体类
-
Mapper接口
-
Mapper映射文件
-
创建逆向工程的步骤
添加依赖和插件
<dependencies>
<!-- MyBatis核心依赖包 -->
<!-- mybatis -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.7</version>
</dependency>
<!-- mysql-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.3</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>
</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>
<!-- 数据库连接池 -->
<dependency>
<groupId>com.mchange</groupId>
<artifactId>c3p0</artifactId>
<version>0.9.2</version>
</dependency>
<!-- mysql-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.3</version>
</dependency>
</dependencies>
</plugin>
</plugins>
</build>
创建逆向工程的配置文件
文件名必须是:
generatorConfig.xml
<?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/mybaties"
userId="root"
password="123">
</jdbcConnection>
<!-- javaBean的生成策略 pojo-->
<javaModelGenerator targetPackage="com.LiuDeHen.pojo" targetProject=".\src\main\java">
<property name="enableSubPackages" value="true" />
<property name="trimStrings" value="true" />
</javaModelGenerator>
<!-- SQL映射文件的生成策略 mapper.xml-->
<sqlMapGenerator targetPackage="com.LiuDeHen.mapper"
targetProject=".\src\main\resources">
<property name="enableSubPackages" value="true" />
</sqlMapGenerator>
<!-- Mapper接口的生成策略 mapper-->
<javaClientGenerator type="XMLMAPPER"
targetPackage="com.LiuDeHen.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>
创建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="jdbc.properties"/>
<typeAliases>
<package name="com.LiuDeHen.pojo"/>
</typeAliases>
<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>
<mappers>
<package name="com.LiuDeHen.mapper"/>
</mappers>
</configuration>
执行MBG插件的generate目标
注意事项:mysql的依赖要和逆向工程插件的mysql依赖版本一样
QBC
查询
-
selectByExample
:按条件查询,需要传入一个example对象或者null;如果传入一个null,则表示没有条件,也就是查询所有数据 -
example.createCriteria().xxx
:创建条件对象,通过andXXX方法为SQL添加查询添加,每个条件之间是and关系 -
example.or().xxx
:将之前添加的条件通过or拼接其他条件
增改
-
updateByPrimaryKey
:通过主键进行数据修改,如果某一个值为null,也会将对应的字段改为null -
mapper.updateByPrimaryKey(new Emp(1,"admin",22,null,"456@qq.com",3));
-
updateByPrimaryKeySelective()
:通过主键进行选择性数据修改,如果某个值为null,则不修改这个字段 -
`mapper.updateByPrimaryKeySelective(new Emp(2,"admin2",22,null,"456@qq.com",3));
15.分页插件
开启分页功能
- 在查询功能之前使用
PageHelper.startPage(int pageNum, int pageSize)
开启分页功能 - pageNum:当前页的页码
- pageSize:每页显示的条数
@Test
public void testPageHelper() throws IOException {
InputStream is = Resources.getResourceAsStream("mybatis-config.xml");
SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(is);
SqlSession sqlSession = sqlSessionFactory.openSession(true);
EmpMapper mapper = sqlSession.getMapper(EmpMapper.class);
//访问第一页,每页四条数据
PageHelper.startPage(1,4);
List<Emp> emps = mapper.selectByExample(null);
emps.forEach(System.out::println);
}
分页相关数据
方法一:直接输出
@Test
public void testPageHelper() throws IOException {
InputStream is = Resources.getResourceAsStream("mybatis-config.xml");
SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(is);
SqlSession sqlSession = sqlSessionFactory.openSession(true);
EmpMapper mapper = sqlSession.getMapper(EmpMapper.class);
//访问第一页,每页四条数据
Page<Object> page = PageHelper.startPage(1, 4);
List<Emp> emps = mapper.selectByExample(null);
//在查询到List集合后,打印分页数据
System.out.println(page);
}
-
分页相关数据:
Page{count=true, pageNum=1, pageSize=4, startRow=0, endRow=4, total=8, pages=2, reasonable=false, pageSizeZero=false}[Emp{eid=1, empName='admin', age=22, sex='男', email='456@qq.com', did=3}, Emp{eid=2, empName='admin2', age=22, sex='男', email='456@qq.com', did=3}, Emp{eid=3, empName='王五', age=12, sex='女', email='123@qq.com', did=3}, Emp{eid=4, empName='赵六', age=32, sex='男', email='123@qq.com', did=1}]
方法二使用PageInfo
- 在查询获取list集合之后,使用
PageInfo<T> pageInfo = new PageInfo<>(List<T> list, intnavigatePages)
获取分页相关数据 - list:分页之后的数据
- navigatePages:导航分页的页码数
@Test
public void testPageHelper() throws IOException {
InputStream is = Resources.getResourceAsStream("mybatis-config.xml");
SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(is);
SqlSession sqlSession = sqlSessionFactory.openSession(true);
EmpMapper mapper = sqlSession.getMapper(EmpMapper.class);
PageHelper.startPage(1, 4);
List<Emp> emps = mapper.selectByExample(null);
PageInfo<Emp> page = new PageInfo<>(emps,5);
System.out.println(page);
}
-
分页相关数据:
PageInfo{ pageNum=1, pageSize=4, size=4, startRow=1, endRow=4, total=8, pages=2, list=Page{count=true, pageNum=1, pageSize=4, startRow=0, endRow=4, total=8, pages=2, reasonable=false, pageSizeZero=false}[Emp{eid=1, empName='admin', age=22, sex='男', email='456@qq.com', did=3}, Emp{eid=2, empName='admin2', age=22, sex='男', email='456@qq.com', did=3}, Emp{eid=3, empName='王五', age=12, sex='女', email='123@qq.com', did=3}, Emp{eid=4, empName='赵六', age=32, sex='男', email='123@qq.com', did=1}], prePage=0, nextPage=2, isFirstPage=true, isLastPage=false, hasPreviousPage=false, hasNextPage=true, navigatePages=5, navigateFirstPage=1, navigateLastPage=2, navigatepageNums=[1, 2]}
-
其中list中的数据等同于方法一中直接输出的page数据
常用数据:
- pageNum:当前页的页码
- pageSize:每页显示的条数
- size:当前页显示的真实条数
- total:总记录数
- pages:总页数
- prePage:上一页的页码
- nextPage:下一页的页码
- isFirstPage/isLastPage:是否为第一页/最后一页
- hasPreviousPage/hasNextPage:是否存在上一页/下一页
- navigatePages:导航分页的页码数
- navigatepageNums:导航分页的页码,[1,2,3,4,5]
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· .NET10 - 预览版1新功能体验(一)