Mybatis
- 什么是框架?
- 软件开发中的一套解决方案,不同的框架可以解决不同的问题。
- 框架的优点:
- 框架封装了很多的细节,使开发者专注于结果或需求
- 使用极简的方式实现功能,提升效率
- 三层框架
- 表现层:用于展示数据的,SpringMVC
- 业务层:是处理业务需求的,
- 持久层:是和数据库进行交互的,MyBatis
1. 概述
Mybatis是用Java编写的一个持久层框架。
封装了很多jdbc操作的很多细节,使开发者只需要关注sql语句本身,无需关心注册驱动,创建连接等。
使用ORM【对象映射关系:将数据库中的表结构与实体类的属性对应起来,让我们操作实体类,就等于操作数据库表】思想实现了结果集的封装。
2. 环境搭建以及入门案例
环境搭建步骤:
-
不使用骨架创建maven工程
-
导入MyBatis及MySQL的jar包坐标【maven配置文件:pom.xml】
- 因为MyBatis是持久层框架,数据库是MySQL所以都要引入
-
创建与数据库相匹配的类【如:User】
-
创建与类对应的dao类【如:UserDao】
-
配置sql相关的主配置文件【如:SqlMapConfig.xml】
- 使用标签配置环境
- 配置SQL环境
- 配置每个dao映射的独立配置路径
- 使用标签配置环境
-
给每一个dao配置独立的映射文件【UserDao.xml】
- 项目概览:
入门案例
入门案例测试步骤:
- 读取配置文件
- 创建SqlSessionFactory工厂
- 这个工厂不能直接创建,需要使用SqlSessionFactoryBuilder的构建者模式
- 创建SqlSession
- 不是真正的创建,是通过工厂模式得到的
- 创建Dao接口的代理对象
- 并不是真正的创建,是通过动态代理的方法的到的
- 执行dao中的方法
- 释放资源
注意:
不要忘记在映射配置中告知mybatis要封装到那个实体类中
配置方式:指定实体类的全限定类名
- Maven配置文件
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.itcast</groupId>
<artifactId>day01_frame_01mybatis</artifactId>
<version>1.0-SNAPSHOT</version>
<!-- 配置打包方式-->
<packaging>jar</packaging>
<!-- 设置导入坐标-->
<dependencies>
<!-- 导入MyBaits坐标-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.4.5</version>
</dependency>
<!-- 设置MySQL坐标-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.22</version>
</dependency>
<!-- Apache为Java提供的日志管理工具-->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.12</version>
</dependency>
<!-- 导入测试单元坐标-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>
- sql相关的主配置文件
<?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">
<!--MyBatis的主配置文件-->
<configuration>
<!--配置环境-->
<environments default="mysql">
<!--配置MySQL的环境-->
<environment id="mysql">
<!--配置事务的类型-->
<transactionManager type="JDBC"></transactionManager>
<!--配置数据源(连接池)-->
<dataSource type="POOLED">
<!--配置数据库的四个连接信息-->
<property name="driver" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/mybatis_itcast?serverTimezone=UTC"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
</dataSource>
</environment>
</environments>
<!--指定映射配置文件的位置,映射配置文件指的是每个dao独立的配置文件-->
<mappers>
<mapper resource="cn/itcast/dao/UserDao.xml"/>
</mappers>
</configuration>
- 每一个dao配置独立的映射文件
<?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">
<!--一个对应的类的一个对应的映射配置文件-->
<mapper namespace="cn.itcast.dao.UserDao">
<!--配置查询所有的标签-->
<select id="findAll" resultType="cn.itcast.bean.User"> -- 这个位置的findAll是查询所有的方法名
select * from user ;
</select>
</mapper>
- 与数据库相匹配的类
//就是普通的User类,getter与setter和tostring不再写了
public class User implements Serializable {
private static final long serialVersionUID = 5091546207423947089L;
private Integer id;
private String username;
private Date birthday;
private String sex;
private String address;
public static long getSerialVersionUID() {
return serialVersionUID;
}
- 类对应的dao类
public interface UserDao {
/**
* 查询所有
* @return
*/
List<User> findAll();
}
- 测试类代码
package cn.itcast.test;
import cn.itcast.bean.User;
import cn.itcast.dao.UserDao;
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 java.io.IOException;
import java.io.InputStream;
import java.util.List;
/**
* mybatis入门使用案例
*/
public class MybatisTest {
public static void main(String[] args) throws IOException {
//使用步骤
// 1、读取配置文件
InputStream is = Resources.getResourceAsStream("SqlMapConfig.xml");
// 2、创建SqlSessionFactory工厂
SqlSessionFactoryBuilder ssfb = new SqlSessionFactoryBuilder();
SqlSessionFactory ssf = ssfb.build(is);
// 3、使用工厂生产SqlSession对象
SqlSession sqlSession = ssf.openSession();
// 4、使用SQL Session创建dao接口的代理对象
UserDao userDao = sqlSession.getMapper(UserDao.class);
// 5、使用代理对象执行方法
List<User> users = userDao.findAll();
for (User user : users) {
System.out.println(user);
}
// 6、释放资源
is.close();
sqlSession.close();
}
}
环境搭建注意事项:
- 创建UserDao.xml和UserDao.java名称不是必须的,在Mybatis中,持久层的操作接口和映射文件也叫做【Mapper】,所以UserDao与UserMapper是一样的
- 在idea中创建目录的时候,直接创建cn.itcast.dao与分开三次创建是不同的,【但目前好像看起来一样】
- 前者为一层
- 后者为三层
- mybatis的映射配置文件位置必须和dao接口的包结构相同
如: User包在cn.itcast.dao中,那么他的映射文件
UserDao.xml就必须在resources中的 cn.itcast.dao中 - 映射配置文件的mapper标签和namespace属性必须是到接口的全限定类名
- 映射配置文件的操作配置(select),id属性必须是dao接口的方法名
- 注意:只要遵循以上的第三、四、五点之后,可以不用再写dao接口的实现类
- 在映射文件的xml中一定要通过resultType来指定返回类型的全限定类名,如下:
<?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">
<!--一个对应的类的一个对应的映射配置文件-->
<mapper namespace="cn.itcast.dao.UserDao">
<!--配置查询所有的标签-->
<select id="findAll" resultType="cn.itcast.bean.User">
-- 这个位置的findAll是查询所有的方法名 --resultType是指定返回类型的全限定类名
select * from user ;
</select>
</mapper>
案例分析
3. 代理Dao实现
注意:
-
在测试保存方法时,我们发现系统给我们关闭了自动提交。所以在代码执行完成之后,我们要手痛提交,【sqlsession.commit();】
-
当我们在每个映射dao的mapper定义时,我们会发现,可以使用两个属性来指定返回值类型,与参数类型
-
resultType:定义返回值类型【一般用于查找】
-
parameterType:定义参数类型【一般用于插入及更新】
-
参数为自定义类型时:需要写全限定类名。如【com.itcast.bean.User】
-
参数为系统内部类型时:可以直接写。如【int,Integer,String】
-
如果定义的方法中,只有一个参数,那么在书写sql语句时,只需要写一个占位符即可,占位符叫什么都可以,还是要见名知意。
例如://删除用户 void deleteUser(Integer id); <delete id="deleteUser" parameterType="int"> delete from user where id = #{id} </delete> 上面的id与下面的id可以名字不一样
-
-
-
当我们定义的参数类型为自定义的类时,如何在select中获取bean的属性呢?
-
直接 #{属性名} 即可
-
如果不是属性,是自定以的get方法,那么需要使用get后名称的首字母大写,来使用,因为系统调用属性,是通过默认的get方法来获取的
-
使用案例:
<mapper namespace="com.itheima.dao.UserDao"> <select id="findAll" resultType="com.itheima.bean.User"> select * from user </select> <insert id="saveUser" parameterType="com.itheima.bean.User"> insert into user (username,address,sex,birthday)values (#{username},#{address},#{sex},#{birthday}) </insert> </mapper>
-
测试代码:
/**
* 测试mybatis的 CRUD
*/
public class MybaitsTest {
private InputStream is;
private SqlSession sqlSession;
private UserDao userDao;
@Before
public void init() throws IOException {
is = Resources.getResourceAsStream("SqlMapConfig.xml");
SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
SqlSessionFactory build = sqlSessionFactoryBuilder.build(is);
sqlSession = build.openSession();
userDao = sqlSession.getMapper(UserDao.class);
}
@After
public void destroy() throws IOException {
is.close();
sqlSession.close();
}
/*
保存一个User
*/
@Test
public void testSave() {
User user = new User();
user.setUsername("张三");
user.setAddress("北京市昌平区");
user.setSex("男");
user.setBirthday(new Date());
userDao.saveUser(user);
sqlSession.commit();
}
实用技巧
模糊查找
在dao的映射文件中,使用模糊查找时,sql语句有两种写法,两种写法可以达到的同样的效果,
-
写法一是用预处理的方式,传入的值应该为 【”%XXX%“】
-
写法二是普通的处理方式,传入值的格式为 【XXX】,但是在语句中,只能够用value书写,不能使用其他的词语替代,不常用
-
select * from user where username like #{username}
-
select * from user where username like '%#{value}%'
保存细节
当我们在id自增的情况下,向数据库插入一条数据时,想获得插入数据的id值,该如何获取
在mybatis中,可以在持久层映射文件相应配置的语句模块中,可以使用一个标签【selectKey】来查找其对应的id。并不会影响其他的使用,方法还想之前一样使用即可,在持久化之后,再打印该对象,就能看到其中的属性了
标签所对应的属性有:
- keyProperty:对应实体类中的字段
- keyColumn:对应数据表中的字段
- resultType:返回值的类型
- order:该语句执行在主SQL语句之前还是之后
- before:之前
- after:之后
使用代码如下:
<insert id="saveUser" parameterType="com.itheima.bean.User">
<selectKey order="AFTER" keyProperty="id" keyColumn="id" resultType="int">
select last_insert_id();
</selectKey>
insert into user (username,address,sex,birthday)values (#{username},#{address},#{sex},#{birthday})
</insert>
OGNL表达式:
Object Graphic Navigation Language
对象 图 导航 语言
- 他是通过对象的取值方法来获取数据,在协防上把get给省略了,像是EL表达式一样
- 比如:我们获取用户的名称:
- 类中的写法:user.getUsername();
- OGNL表达式写法:user.username
- mybatis中为什么可以直接写username,而不用user。呢
- 因为在parameterType中已经提供了属性所属的类,所以就不用写对象名了
也可以以VOJO中的属性为参数来书写SQL语句
- VOJO类中的属性,必须有set和get方法
映射文件中的配置
<!-- 通过VOJO中的属性模糊查找-->
<select id="findByVojo" parameterType="com.itheima.bean.QueryVo" resultType="com.itheima.bean.User">
select * from user where username like #{user.username}
</select>
定义功能时:
//通过VOJO来模糊查询
List<User> findByVojo(QueryVo vo);
测试代码:
@Test
public void findByVojo() {
QueryVo vo = new QueryVo();
User user = new User();
user.setUsername("%王%");//想要模糊查询就得设置%,不想使用模糊查询就不需要了
vo.setUser(user);
List<User> byVojo = userDao.findByVojo(vo);
for (User user1 : byVojo) {
System.out.println(user1);
}
}
解决类属性与数据库列名不对应问题
如果数据库中的列名与实体类中的属性名不一样时,有两种方法可以解决
-
查询时,给列表起别名,推荐【执行效率高】
-
也可以在外面使用标签进行单独配置
-
中的id属性:引用使用
-
type:bean对应的全限定类名
- id标签体:设置主键对应
- result标签体:设置普通字段对应
- property属性:备案中的属性
- column属性:表中的列名
-
具体使用如下:
<resultMap id="userMap" type="com.itheima.bean.User"> <id property="userId" column="id"/> <result property="userName" column="username"/> <result property="userBirthday" column="birthday"/> <result property="userSex" column="sex"/> <result property="userAddress" column="address"/> </resultMap> <!-- 查找所有user--> <select id="findAll" resultMap="userMap"> --方法一 -- select id userId,username userName,birthday userBirthday,sex userSex,address userAddress from user --方法二 select * from user </select>
4. 编写Dao实现类
查询过程分析:
mybatis在执行自己写的dao的语句时,会先 找到一个了selectList的类,然后继续向下执行,最终还是调用JDBC中PreparedStatement对象
PreparedStatement对象的执行方法
- execute:它能执行CRUD中的任何一种语句。他的返回值是一个Boolean类型,表示是否有结果集
- true:有结果集,
- false:没有结果集
- executeUpdate:它只能执行CUD【增删改】语句,查询语句无法执行,他的返回值是影响数据库记录的行数
- executeQuery:它只能执行查询语句,无法执行增删改,执行结果封装的结果集是ResultSet对象
增删改过程分析:
5. MyBatis全局配置文件
mybatis.xml中的标签
5.1 properties标签
在配置数据库连接时,也可以使用外部的配置文件解决,数据库的基本信息,如url,username,等
通过标签配置即可,在读取标签内容时,如果标签内部和引入资源的文件相同,则引入资源文件的name属性会将标签体内部中的值覆盖。且引入外部文件时有两种配置方法,如下:
- 使用resource属性配置:一般使用项目路径即可,resources为根目录,直接书写即可
- 使用url属性配置:
- 要求有协议名称,主机名,端口号等信息,才可以使用
- 避免路径中有中文字符,否则路径会乱码
- 如:【file:///D:/HLMJ/launchcfg.xml】/【https://home.firefoxchina.cn/】
- 配置之后,直接使用【${配置文件中的属性名称}】即可
5.2 settings标签
对mybatis进行配置
通过setting标签中的 子标签来设置,name为属性名,value值要修改的值
- cacheEnabled
- 缓存的全局开关
- 默认为true
- lazyLoadingEnabled
- 延迟加载的全局开关
- 默认为false
- aggressiveLazyLoading
- 开启时,任一方法的调用都会加载该对象的所有延迟加载属性。否则,每个延迟加载属性会按需加载
- 默认为false (在 3.4.1 及之前的版本中默认为 true)
- useGeneratedKeys
- 允许 JDBC 支持自动生成主键,需要数据库驱动支持。如果设置为 true,将强制使用自动生成主键。尽管一些数据库驱动不支持此特性,但仍可正常工作(如 Derby)
- 默认为false
- autoMappingBehavior
- 指定 MyBatis 应如何自动映射列到字段或属性。
- NONE 表示关闭自动映射;
- PARTIAL 只会自动映射没有定义嵌套结果映射的字段。
- FULL 会自动映射任何复杂的结果集(无论是否嵌套)。
- 默认为partial
- 指定 MyBatis 应如何自动映射列到字段或属性。
- mapUnderscoreToCamelCase
- 是否开启驼峰命名自动映射,即从经典数据库列名 A_COLUMN 映射到经典 Java 属性名 aColumn
- 默认为false
<?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="druid.properties"></properties>
<!-- 对mybatis进行设置-->
<settings>
<!-- 开启驼峰自动命名-->
<setting name="mapUnderscoreToCamelCase" value="true"/>
<!-- -->
</settings>
<!-- 配置数据库连接-->
<environments default="mysql">
<environment id="mysql">
<transactionManager type="jdbc"></transactionManager>
<dataSource type="POOLED">
<property name="driver" value="${jdbc.driverClassName}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="com/atguigu/mybatis/mapper/EmployeeMapper.xml"></mapper>
</mappers>
</configuration>
5.3 typeAliases标签
【typeAliases】 标签,通过其多个【typeAlias】子标签可以给多个表起别名,通过配置其多个【package】可以给多个包起别名
在SQLMapConfig.xml配置别名之后,在每个dao的映射文件的xml中,即可使用别名
-
typeAlias标签用于给类配置别名
- 配置别名之后,别名不区分大小写限制。
- 通过type属性指定数据源的全限定类名
-
通过alias属性指定别名
- 如果在配置标签之后,没有使用为其指定别名,默认别名为类名字首字母小写
-
package子标签用于给包配置别名
- 使用name属性来指定包的全限定包名
- 该报下的实体类都会注册别名,包名就是别名,不再区分大小写
- 注:package在不用的位置,作用不一样,只有在typeAliases标签中,才是此作用
- 当package在mappers中,用于指定dao接口所在的包,当指定以后就不需要再写mapper以及resource或者class了
<?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="druid.properties"></properties>
<typeAliases>
<!-- 给表配置别名-->
<typeAlias type="com.itheima.bean.User" alias="user"></typeAlias>
<!-- 给包中的所有类配置别名-->
<package name="com.itheima.bean"/>
</typeAliases>
<!-- 配置环境-->
<environments default="mysql">
<!-- 配置mysql环境 -->
<environment id="mysql">
<transactionManager type="JDBC"></transactionManager>
<dataSource type="POOLED">
<property name="driver" value="${jdbc.driverClassName}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</dataSource>
</environment>
</environments>
<!-- 配置映射文件位置-->
<mappers>
<!--给单独一个dao配置映射文件位置-->
<mapper resource="com/itheima/dao/UserDao.xml"></mapper>
<!-- 给包中的所有dao配置映射文件位置-->
<package name="com.itheima.bean"/>
</mappers>
</configuration>
5.4 typeHandlers标签
自定义类型处理器,通过重写类型处理器或创建类型处理器来处理不支持或非标准的类型
如何实现:
- 实现org.apache.ibatis.type.TypeHandler接口
- 或继承org.apache.ibatis.type.BaseTypeHandler类
- 指定映射某个JDBC的类型(可选)
- 在mybatis全局配置文件中进行注册
5.5 连接池与事务
在ssm框架整合之后,该部分不需要自己配置,交给spring来解决
5.5.1. 连接池
减少获取连接的次数与消耗的时间
连接池就是用于存储连接的一个容器,
容器其实就是一个集合对象,该对象必须是【线程安全】的,不能两个线程拿到同一个连接,该集合还必须实现队列的特性,即【先进先出】
5.5.2. Mybatis中的连接池
mybatis连接池提供了三种配置方式:
- 配置位置:
- 主配置文件SQL Map Config.xml文中的dataSource标签,通过标签的type属性来指定不同的连接池类型
- type的三种取值
- POOLED
- 采用传统的javax.sql.DataSource规范中的连接池,
- mybatis中有针对规范的实现
- UNPOOLED
- 采用传统的获取连接的方式,也实现了传统的javax.sql.DataSource接口
- 就是没有使用池。获取连接池采用直接new的方式,用完之后直接销毁。
- JNDI
- 采用服务器提供的JNDI技术实现,来获取DataSource对象,
- 不同的服务器能拿到不同的DataSource对象
- 如果不是web或maven的var工程,是不能使用的。
- POOLED
使用tomcat服务器时,采用的连接池为dbcp连接池。通过查找数据,我们会发现,dbcp连接池的初始化连接数量为30个, removeAbandonedTimeout 为180秒,即一个用完后的连接会等待180秒,如果在180秒内没有被再次使用,就会重新放回到连接池当中。
5.6 databaseIdProvider标签
如果想要让整个系统可以适应多个数据库,写多中sql语句时,可以通过该标签在mybatis的主配置文件中使用标签来设置数据库厂商标识
name:数据库厂商标识
value:为标识起一个别名,方便SQL语句使用databaseId属性引用
<!--设置数据库厂商标识-->
<databaseIdProvider type="DB_VENDOR">
<property name="MySQL" value="mysql"/>
<property name="Oracle" value="oracle"/>
</databaseIdProvider>
在配置了databaseIdProvider之后,在SQL映射文件中的增删改查的标签中就可以用databaseId属性来指定数据库标识的别名。例如:
<select id="getEmployeeById" resultType="employee" databaseId="mysql">
select id,last_name,email,salary,dept_id
from employees
where id = #{id}
</select>
6. mybatis映射文件配置
对于mybatis来说,一般不需要我们自己实现mapper接口(可以自己实现,但是没必要),我们只需要统配mybatis的映射文件来设置mysql语句即可。
- 在SQL映射文件中需要注意的几个元素标签
- cache:该空间缓存配置
- cache-ref:引用其他空间的缓存配置
- sql:可以被其他引用的可重用语句块
- 增删改查对应相对应的关键字即可
6.1 mybatis中的CRUD
6.1.1 Select
在mybatis中是不支持last_name自动转化为lastName(驼峰命名)的,在这种情况下,我们有三种方式来解决该问题,
-
通过给查询的列 起别名的方式,让其别名与bean中的属性名称相同
-
通过mybatis的全局配置文件中的setting标签中的mapUnderscoreToCamelCase属性,来开启命名自动转换,具体可以看5.2中
-
第三种是通过在其对应的映射文件中使用resultMap来讲表中的列名与bean中的属性一一对应。
<resultMap id="userMap" type="com.itheima.bean.User"> <id property="userId" column="id"/> <result property="userName" column="username"/> <result property="userBirthday" column="birthday"/> <result property="userSex" column="sex"/> <result property="userAddress" column="address"/> </resultMap>
当我们在查询情况中,所需要的返回值可能有几种方案,
-
返回值为基本数据与其包装类型:如int、double、Integer等
- 在返回值resultType属性中,直接可以使用其名称(不区分大小写),不需要写全限定类名,因为在系统内部以及为其起过别名了
-
返回值为一个自定义Bean时
- resultType属性为其全限定类名即可
- 当我们为bean起别名之后,也可以使用别名
-
当我们返回值为一个List集合时,resultType属性为list所指定的泛型的名称
-
当我们返回值为map类型时,resultType属性为map
-
查询结果为一个对象,
- map的key就是列名
- map的值就是列数据
-
当查询结果为多个对象时,
-
首先我们要在其方法定义的上方,使用@KeyMap来指定一个可以用来唯一标识该数据的列(通常该列就是我们表中的主键,因为map集合中是不允许重复数据的,如果使用其他,可能会造成数据丢失),且map的key应该与定义唯一标识的列类型相同
-
其他均与单个对象的map相同
-
使用案例:
@MapKey("id") Map<Integer,Object> getEmployeesMaps(); <select id="getEmployeesMaps" resultType="map"> select id,last_name,email,salary,dept_id from employees </select>
-
-
查询使用案例
<select id="getEmployeeById" parameterType="integer" resultType="com.atguigu.mybatis.entities.Employee">
select id,last_name from employees
where id = #{id}
</select>
6.1.2 insert
-
mapper接口方法
void addEmployee(Employee employee);
-
mapper映射文件
<!-- parameterType属性:设置请求参数的类型的全类名,该属性也可以不指定, MyBatis 可以通过类型处理器推断出具体传入语句的参数 --> <insert id="addEmployee" parameterType="com.atguigu.mybatis.entities.Employee"> insert into employees(last_name,email,salary,dept_id) values(#{lastName},#{email},#{salary},#{deptId}) </insert>
获取添加数据之后的主键值
<selectKey order="AFTER" keyProperty="id" keyColumn="id" resultType="int">
select last_insert_id();
</selectKey>
如何使用:
<insert id="addEmployee" parameterType="com.atguigu.mybatis.entities.Employee">
<selectKey order="AFTER" keyProperty="id" keyColumn="id" resultType="int">
select last_insert_id();
</selectKey>
insert into employees(last_name,email,salary,dept_id)
values(#{lastName},#{email},#{salary},#{deptId})
</insert>
6.1.3 update
接口方法
void updateEmployee(Employee employee);
映射文件
<update id="updateEmployee">
update employees set
last_name=#{lastName},
email=#{email},
salary=#{salary},
dept_id=#{deptId}
where id=#{id}
</update>
6.1.4 delete
使用基本如上update
6.2 insert、update、delete标签属性说明
-
flushCache:将其设置为 true 后,只要语句被调用,都会导致本地缓存和二级缓存被清空,默认值:(对 insert、update 和 delete 语句)true。
-
useGeneratedKeys:(仅适用于 insert 和 update)这会令 MyBatis 使用 JDBC 的 getGeneratedKeys 方法来取出由数据库内部生成的主键(比如:像 MySQL 和 SQL Server 这样的关系型数据库管理系统的自动递增字段),默认值:false。
-
keyProperty:(仅适用于 insert 和 update)指定能够唯一识别对象的属性,MyBatis 会使用 getGeneratedKeys 的返回值或 insert 语句的 selectKey 子元素设置它的值,默认值:未设置(unset)。如果生成列不止一个,可以用逗号分隔多个属性名称。
-
keyColumn:(仅适用于 insert 和 update)设置生成键值在表中的列名,在某些数据库(像 PostgreSQL)中,当主键列不是表中的第一列的时候,是必须设置的。如果生成列不止一个,可以用逗号分隔多个属性名称。
6.3 主键生成方式、获取主键
- 支持主键自增,例如MySQL数据库
- 不支持主键自增,例如Oracle数据库
6.3.1 支持主键自动生成(例如MySQL)
若数据库支持自动生成主键的字段(比如 MySQL 和 SQL Server),则可以设置 useGeneratedKeys=”true”,然后再把 keyProperty 设置到目标属性上。
<insert id="addEmployee" useGeneratedKeys="true" keyProperty="id">
insert into employees(last_name,email,salary,dept_id)
values(#{lastName},#{email},#{salary},#{deptId})
</insert>
不持支主键自动生成(例如Oracle)
而对于不支持自增型主键的数据库(例如 Oracle),则可以使用 selectKey 子元素:selectKey 元素将会首先运行,id 会被设置,然后插入语句会被调用。
<insert id="addEmployee" databaseId="oracle">
<selectKey order="BEFORE" keyProperty="id" resultType="integer">
select employee_seq.nextval from dual
</selectKey>
insert into oracle_employees(id,last_name,email,salary,dept_id)
values(#{id},#{lastName},#{email},#{salary},#{deptId})
</insert>
或者
<insert id="addEmployee" databaseId="oracle">
<selectKey order="AFTER" keyProperty="id" resultType="integer">
select employee_seq.currval from dual
</selectKey>
insert into oracle_employees(id,last_name,email,salary,dept_id)
values(employee_seq.nextval,#{lastName},#{email},#{salary},#{deptId})
</insert>
6.4 resultMap自定义映射
resultMap与resultType两个结果类型只能二选一
-
resultMap,实现高级结果集映射
-
id :用于完成主键值的映射
-
result :用于完成普通列的映射
-
association :一个复杂的类型关联;许多结果将包成这种类型
-
collection : 复杂类型的集
<resultMap id="myEmp" type="com.atguigu.mybatis.entities.Employee"> <id column="id" property="id"></id> <result column="last_name" property="lastName"></result> </resultMap> <select id="getEmployeeById" resultMap="myEmp"> select * from employees where id = #{id} </select>
6.5 参数传递
- 如若不指定参数名称:
- 默认使用arg0、arg1、param1,param2
- 可以在方法定义时,使用@param注解来定义参数名称
- 这是只能使用定义的参数名称、param1,param2
- 当参数为POJO对象时,直接使用POJO对象的属性名即可
- 当参数对象为多个时,也可以封装到map中进行传输使用
7. 自定义映射以及级联属性赋值
通过自定义resultMap来让数据库中的字段【或使用聚合函数之后的字段】匹配到指定POJO的属性中,可以方便我们对于数据的封装
其中resultMap常用的子标签有:
- id :用于完成主键值的映射
- result :用于完成普通列的映射
- association :一个复杂的类型关联;许多结果将包成这种类型,常用于一对一表数据查询
- collection :复杂类型的集,常用于一对多表数据查询
在我们查询表的时候,从SQL语句的数量分类:
- 单表查询
- 多表查询
- 连接查询
- 一对一表数据查询
- 一对多表数据查询
- 嵌套查询(分步查询)
- 一对一表数据查询
- 一对多表数据查询
- 连接查询
7.1 连接查询__一对一表数据查询
级联属性直接赋值
<resultMap id="myEmp" type="com.atguigu.mybatis.entities.Employee">
<id column="id" property="id"></id>
<result column="last_name" property="lastName"></result>
<result column="email" property="email"></result>
<result column="salary" property="salary"></result>
<result column="d_id" property="department.id"></result>
<result column="d_name" property="department.name"></result>
</resultMap>
通过关键字来给级联属性赋值
设置自定义映射,且id唯一
<resultMap id="myEmp2" type="com.atguigu.mybatis.entities.Employee">
设置主键对应的字段属性
<id column="id" property="id"></id>
设置普通字段属性
<result column="last_name" property="lastName"></result>
<result column="email" property="email"></result>
<result column="salary" property="salary"></result>
通过propertiy设置级联属性中的属性名,Javatype为被包含属性的全限定类名
<association property="department" javaType="com.atguigu.mybatis.entities.Department">
设置级联属性中的主键属性
<id column="d_id" property="id"></id>
设置级联属性中的普通属性
<result column="d_name" property="name"></result>
</association>
</resultMap>
<!--单记录分布查询-->返回结果map为上面指定的唯一id
<select id="getEmployeeByIdContainsDept" resultMap="myEmp2">
SELECT e.id,e.last_name,e.email,e.salary,d.id d_id,d.name d_name
FROM employees e LEFT JOIN departments d
on e.dept_id = d.id
WHERE e.id= #{id}
</select>
7.2 嵌套查询__一对多表数据查询
如果我们写一条SQL语句有难度时,我们可以选择分步查询来解决面对的问题
当我们使用分步查询时,通常在一个查询的内部会用到另一个mapper中的查询语句,所以要有两条sql语句存在在不用的mapper中。
一对一表分步查询
主表查询
<!--用于单记录分布查询-->
<resultMap id="myDept" type="com.atguigu.mybatis.entities.Employee">
映射主键的一列
<id column="id" property="id"></id>
<!--映射其他列-->
<result column="last_name" property="lastName"></result>
<result column="email" property="email"></result>
<result column="salary" property="salary"></result>
<!--分布查询
property:级联的属性
select:用于查找级联内容的查询语句,这里采用全限定类名加方法名的方式,可以有一个条件或者多个条件
column:查找级联内容的条件
当我们只有一个条件时,直接 column = "随便"
当我们有多个条件时,{key1=value1,key2=value2...}
-->
<association property="department" select="com.atguigu.mybatis.mapper.DepartmentMapper.getDepartmentById"
column="dept_id"></association>
</resultMap>
子表查询
<select id="getDepartmentById" resultType="com.atguigu.mybatis.entities.Department">
SELECT id,name
FROM departments
如果在查询时有多个条件,这里#{}中的内容不可以随便写,
必须值为主表查询中设置的key键,否则会参数传递失败
WHERE id= #{id}
</select>
一对多表联合查询
<select id="getEmployeesByDeptId" resultMap="myDept3">
SELECT d.id,d.name,e.id eId,e.last_name,e.email,e.salary
FROM departments d LEFT JOIN employees e
ON d.id = e.dept_id
WHERE d.id=#{deptId}
</select>
<resultMap id="myDept3" type="com.atguigu.mybatis.entities.Department">
<id column="id" property="id"></id>
<result column="name" property="name"></result>
<collection property="emps" ofType="com.atguigu.mybatis.entities.Employee" column="d.id">
<id column="eId" property="id"></id>
<result column="last_name" property="lastName"></result>
<result column="email" property="email"></result>
<result column="salary" property="salary"></result>
</collection>
</resultMap>
7.2.1 延迟加载
延迟加载也就是懒加载,在我们分步查询数据库时,如果有一些子表查询中的字段没有被使用或获取过,那么系统将不给我们发送SQL语句查询,只有在我们使用之前,系统才会发送请求
-
想要开启延迟加载,首先我们要在MyBatis的全局配置文件中的setting标签中设置如下两个属性
-
lazyLoadingEnabled:懒加载全局开关
-
aggressiveLazyLoading:单独方法按需加载开关
<settings> <!--数据库字段名与JavaBean属性之间的转换大小写--> <setting name="mapUnderscoreToCamelCase" value="true"/> <!--开启全局懒加载--> <setting name="lazyLoadingEnabled" value="true"/> <!--它是控制具有懒加载特性的对象的属性的加载情况的。 true表示如果对具有懒加载特性的对象的任意调用会导致这个对象的完整加载,false表示每种属性按照需要加载。 --> <setting name="aggressiveLazyLoading" value="false"/> </settings>
-
-
然后还需要在我们SQL映射文件中的方法内进行开启,
-
注意,
-
这里的fetchType有两个属性,分别为lazy【懒加载】与eager【及时加载】
-
这里的开启会覆盖单独方法的加载开关
-
只有打开懒加载的全局开关,这里的开关才可以生效
<collection property="emps" select="com.atguigu.mybatis.dao.EmployeeMapper.getEmployeesByDeptId" column="id" fetchType="lazy"></collection>
-
-
7.2.2 多参数传递
我们在分步查询时,可能会有多个条件,
- 如果分步查询时,需要传递给调用的查询中多个参数,则需要将多个参数封装成
Map来进行传递,语法如下: {k1=v1, k2=v2…}
- 在所调用的查询方法取值时就要参考Map的取值方式,需要严格的按照封装map
时所用的key来取值.
8. 动态SQL
为了方便查询发明,解决我们在CRUD时可能会出现的各种尴尬问题,mybatis内部给我们创建了动态sql的语法【OGNL】。简单标签的使用,能是我们更加注重于SQL语句本身。
- OGNL( Object Graph Navigation Language )对象图导航语言,这是一种强大的表达式语言,通过它可以非常方便的来操作对象属性。 类似于我们的EL,SpEL等
- 访问对象属性: person.name
- 调用方法: person.getName()
- 调用静态属性/方法: @java.lang.Math @PI @java.util.UUID @randomUUID()
- 调用构造方法: new com.atguigu.bean.Person(‘admin’).name
- 运算符: +,-*,/,%
- 逻辑运算符: in,not in,>,>=,<,<=,==,!=
注意:xml中特殊符号如 ” , > , < 等这些都需要使用转义字符
8.1 常用的几个转义字符
【”】"
【>】>
【<】<
【空格】
8.2 常用的标签有:
- if标签:通用
- 用来判断是否该参数为空,
- where标签:用于条件查询中
- 可以自动去掉if标签中前面的and或者or
- trim标签:用于条件查询中,与where标签大同小异,通过属性设置不同效果
- 可以自动去掉if标签中后面的and或者or
- prefix:添加前缀
- prefixOverrides:去掉前缀
- suffix:添加后缀
- suffixOverrides:去掉后缀
- 可以自动去掉if标签中后面的and或者or
- set标签:用于update语句中
- 可以自动去掉if或where标签中后面的逗号【,】
- choose标签:类似于switch case default 的功能一样,该标签不会像swith一样拥有穿透功能,不需要在子标签结束之前使用break;类似的语句
- choose:相当于switch
- when:相当于 case
- otherwise:相当于default
- foreach标签:我们在写SQL语句时,可能会用到in(。。。),且此时,我们又不知道括号内到底有多少的数据。我们就可以用到foreach来解决,简单介绍一个内部的属性
- collection:数据源的名称
- item:读到的数据变量名
- open:开始标记
- close:结束标记
- separater:分隔符
- index:下标
- sql标签:提高通用sql语句的复用率(避免重复代码写多次),也可以降低耦合度
- 在设置时,我们会给该标签设置唯一的id
- 在使用时,我们只要在sql语句对应的标签内部,通过include标签直接引用即可
8.3 示例代码:
where与if
<select id="getEmployee" resultType="com.atguigu.mybatis.entities.Employee">
select id,last_name,email,salary from employees
<where>
<if test=" id != null">
and id = #{id}
</if>
<if test="lastName != null and lastName != '' ">
and last_name = #{lastName}
</if>
</where>
</select>
trim
<select id="getEmployeeByConditionIf" resultType="com.atguigu.mybatis.entities.Employee">
select id,last_name,email,salary
from employees
<trim prefix="where" suffixOverrides="and">
<if test="id!=null">
id=#{id} and
</if>
<if test="lastName!=null&&lastName!=""">
last_name=#{lastName} and
</if>
<if test="email!=null and email.trim()!=''">
email=#{email} and
</if>
<if test="salary!=null">
salary=#{salary}
</if>
</trim>
set
<!-- 测试set-->
<update id="updateEmployeeBySet">
update employees
<set>
<if test="lastName != null">
last_name = #{lastName},
</if>
<if test="email != null">
email = #{email},
</if>
<if test="salary != null">
salary = #{salary},
</if>
</set>
where id = #{id}
</update>
choose
<!--测试choose标签-->
<select id="getEmployeeByChoose" resultType="com.atguigu.mybatis.entities.Employee">
select id,last_name,email,salary from employees
<where>
<choose>
<when test="id != null">
and id = #{id}
</when>
<when test="lastName != null and lastName != '' ">
and last_name = #{lastName}
</when>
<when test="email != null && email != "" ">
and email = #{email}
</when>
<otherwise>
and salary = #{salary}
</otherwise>
</choose>
</where>
</select>
foreach
<!-- 测试ForEach 标签-->
<select id="getEmployeesByForEach" resultType="com.atguigu.mybatis.entities.Employee">
<include refid="selectSql"></include>
where id in
<foreach collection="ids" item="id" open="(" close=")" separator="," index="">
#{id}
</foreach>
</select>
9. mybatis缓存机制
分别由一级缓存与二级缓存
- 一级缓存就是存放在sqlsession中
- 清空条件
- 当sql关闭连接或commit之后
- 两次查询间执行增删改
- 手动清空
- 清空条件
- 二级缓存存放在全局作用域中,想要使用需要现在全局配置文件中开启
- 注意事项
- 缓存实现要求POJO实现Serializable接口
- SqlSession 关闭或提交之后
- 回收策略 eviction=“FIFO”:默认的是 LRU。
- LRU – 最近最少使用的
- FIFO – 先进先出
- SOFT – 软引用 : 软引用通常用在对内存敏感的程序中
- WEAK – 弱引用 : 不管JVM的内存空间是否足够,总会回收该对象占用的内存。
- 注意事项
10. 逆向工程
简称MBG,可以帮助我们快速的生成对应的映射文件,接口,以及Bean类,支持简单的增删改,复杂sql的定义仍需要我们自己手动写
- 官方文档地址:http://www.mybatis.org/generator/
- 官方工程地址:https://github.com/mybatis/generator/releases
注意:在使用MySQL 8.X 的版本,偶尔会发生串数据库的现象,我们需要在jdbcConnection的标签中,添加一段代码
<property name="nullCatalogMeansCurrent" value="true"></property>
10.1 快速入门:
-
导入逆向工程jar包
- mybatis-generator-core-1.3.2.jar
-
编写mbg的配置文件
<!DOCTYPE generatorConfiguration PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN" "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd"> <generatorConfiguration> <!-- id属性:设置一个唯一标识 targetRuntime属性值说明: MyBatis3Simple:基本的增删改查 MyBatis3:带条件查询的增删改查 --> <context id="simple" targetRuntime="MyBatis3Simple"> <!--设置连接数据库的相关信息--> <jdbcConnection driverClass="com.mysql.jdbc.Driver" connectionURL="jdbc:mysql://localhost:3306/mybatis" userId="root" password="root"/> <!--设置JavaBean的生产策略--> <javaModelGenerator targetPackage="com.atguigu.mybatis.mbg.beans" targetProject="src"/> <!--设置SQL映射文件的生产策略--> <sqlMapGenerator targetPackage="com.atguigu.mybatis.mbg.mapper" targetProject="src"/> <!--设置Mapper接口的生产策略--> <javaClientGenerator type="XMLMAPPER" targetPackage="com.atguigu.mybatis.mbg.mapper" targetProject="src"/> <!--逆向分析的表--> <table tableName="employees" domainObjectName="Employee"/> <table tableName="departments" domainObjectName="Department"/> </context> </generatorConfiguration>
-
参考官方文档创建代码生成器运行代码
@Test public void testMGB() throws IOException, XMLParserException, InvalidConfigurationException, SQLException, InterruptedException { List<String> warnings = new ArrayList<String>(); boolean overwrite = true; File configFile = new File("mbg.xml"); ConfigurationParser cp = new ConfigurationParser(warnings); Configuration config = cp.parseConfiguration(configFile); DefaultShellCallback callback = new DefaultShellCallback(overwrite); MyBatisGenerator myBatisGenerator = new MyBatisGenerator(config, callback, warnings); myBatisGenerator.generate(null); }
10.2 测试及使用
10.2.1 基本测试:
/*
测试获取一个对象
*/
@Test
public void testSelectByPrimaryKey() throws IOException {
//设置MyBatis全局配置文件的路径
String resource = "mybatis-config.xml";
//读取类路径下的配置文件得到输入流
InputStream inputStream = Resources.getResourceAsStream(resource);
//创建SqlSessionFactory对象
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
//获取SqlSession对象,相当于Connection对象
SqlSession sqlSession = sqlSessionFactory.openSession();
try {
//获取Mapper代理对象
EmployeeMapper mapper = sqlSession.getMapper(EmployeeMapper.class);
Employee employee = mapper.selectByPrimaryKey(1);
System.out.println(employee);
} finally {
//关闭sqlSession
sqlSession.close();
}
}
10.2.2 简单条件查询:
@Test
public void testSelectByExample() throws IOException {
//设置MyBatis全局配置文件的路径
String resource = "mybatis-config.xml";
//读取类路径下的配置文件得到输入流
InputStream inputStream = Resources.getResourceAsStream(resource);
//创建SqlSessionFactory对象
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
//获取SqlSession对象,相当于Connection对象
SqlSession sqlSession = sqlSessionFactory.openSession();
try {
//获取Mapper代理对象
EmployeeMapper mapper = sqlSession.getMapper(EmployeeMapper.class);
//创建EmployeeExample对象
EmployeeExample employeeExample = new EmployeeExample();
//创建Criteria对象
EmployeeExample.Criteria criteria = employeeExample.createCriteria();
//查询名字里包含a并且工资大于等于10000的员工
criteria.andLastNameLike("%a%").andSalaryGreaterThanOrEqualTo(10000.00);
List<Employee> employees = mapper.selectByExample(employeeExample);
for (Employee employee : employees) {
System.out.println(employee);
}
} finally {
//关闭sqlSession
sqlSession.close();
}
}
10.2.3 复杂条件查询:
@Test
public void testSelectByExample() throws IOException {
//设置MyBatis全局配置文件的路径
String resource = "mybatis-config.xml";
//读取类路径下的配置文件得到输入流
InputStream inputStream = Resources.getResourceAsStream(resource);
//创建SqlSessionFactory对象
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
//获取SqlSession对象,相当于Connection对象
SqlSession sqlSession = sqlSessionFactory.openSession();
try {
//获取Mapper代理对象
EmployeeMapper mapper = sqlSession.getMapper(EmployeeMapper.class);
//创建EmployeeExample对象
EmployeeExample employeeExample = new EmployeeExample();
//创建Criteria对象
EmployeeExample.Criteria criteria = employeeExample.createCriteria();
//查询名字里包含a的员工
criteria.andLastNameLike("%a%");
EmployeeExample.Criteria criteria1 = employeeExample.createCriteria();
//查询工资小于等于10000的员工
criteria1.andSalaryLessThanOrEqualTo(10000.00);
//使用or关联两个Criteria对象
employeeExample.or(criteria1);
List<Employee> employees = mapper.selectByExample(employeeExample);
for (Employee employee : employees) {
System.out.println(employee);
}
} finally {
//关闭sqlSession
sqlSession.close();
}
}
11. PageHelper分页插件
在mybatis中常用的第三方插件,官方文档为:https://github.com/pagehelper/Mybatis-PageHelper/blob/master/README_zh.md
11.1 快速入门
-
导入jar包
- pagehelper-5.0.0.jar
- jsqlparser-0.9.5.jar(该包为依赖jar包)
-
在MyBatis全局配置文件中配置分页插件
<plugins> <!--配置PageHelper分页插件--> <plugin interceptor="com.github.pagehelper.PageInterceptor"></plugin> </plugins>
-
使用PageHelper提供的方法进行分页
-
可以使用更强大的PageInfo封装返回结果
page对象的使用:
@Test
public void testPageHelper() throws IOException {
//设置MyBatis全局配置文件的路径
String resource = "mybatis-config.xml";
//读取类路径下的配置文件得到输入流
InputStream inputStream = Resources.getResourceAsStream(resource);
//创建SqlSessionFactory对象
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
//获取SqlSession对象,相当于Connection对象
SqlSession sqlSession = sqlSessionFactory.openSession();
try {
//获取Mapper代理对象
EmployeeMapper mapper = sqlSession.getMapper(EmployeeMapper.class);
//设置分页信息,每页显示3条记录,获取第1页
Page<Object> page = PageHelper.startPage(1, 3);
//获取所有员工
List<Employee> employees = mapper.getEmployees();
System.out.println("当前页是:"+page.getPageNum());
System.out.println("每页显示的条数是:"+page.getPageSize());
System.out.println("总页数是:"+page.getPages());
System.out.println("总记录数是:"+page.getTotal());
System.out.println("当前页中的记录有:");
for (Employee employee : employees) {
System.out.println(employee);
}
} finally {
//关闭sqlSession
sqlSession.close();
}
}
pageInfo对象:
pageInfo的功能比page对象的功能还要强大, 包括是否为首页末页,前后是否还有页码等。
@Test
public void testPageHelper() throws IOException {
//设置MyBatis全局配置文件的路径
String resource = "mybatis-config.xml";
//读取类路径下的配置文件得到输入流
InputStream inputStream = Resources.getResourceAsStream(resource);
//创建SqlSessionFactory对象
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
//获取SqlSession对象,相当于Connection对象
SqlSession sqlSession = sqlSessionFactory.openSession();
try {
//获取Mapper代理对象
EmployeeMapper mapper = sqlSession.getMapper(EmployeeMapper.class);
//设置分页信息
Page<Object> page = PageHelper.startPage(4, 2);
//获取所有员工
List<Employee> employees = mapper.getEmployees();
//创建PageInfo对象设置每页只显示5个页码
PageInfo<Employee> pageInfo = new PageInfo<>(employees, 5);
System.out.println("当前页是:"+pageInfo.getPageNum());
System.out.println("每页显示的条数是:"+pageInfo.getPageSize());
System.out.println("总页数是:"+pageInfo.getPages());
System.out.println("总记录数是:"+pageInfo.getTotal());
System.out.println("是否有上一页:"+pageInfo.isHasPreviousPage());
System.out.println("上一页是:"+pageInfo.getPrePage());
System.out.println("是否有下一页:"+pageInfo.isHasNextPage());
System.out.println("下一页是:"+pageInfo.getNextPage());
System.out.println("是否是第一页:"+pageInfo.isIsFirstPage());
System.out.println("是否是最后一页:"+pageInfo.isIsLastPage());
System.out.println("导航页的第一个页码是:"+pageInfo.getNavigateFirstPage());
System.out.println("导航页的最后一个页码是:"+pageInfo.getNavigateLastPage());
System.out.println("导航页的总页码是:"+pageInfo.getNavigatePages());
System.out.println("当前页中的记录有:");
for (Employee employee : employees) {
System.out.println(employee);
}
System.out.println("页码信息:");
int[] navigatepageNums = pageInfo.getNavigatepageNums();
for (int navigatepageNum : navigatepageNums) {
System.out.print(navigatepageNum+" ");
}
} finally {
//关闭sqlSession
sqlSession.close();
}
}