MyBatis是一个非常流行的Java持久层框架,它简化了数据库操作的代码。分页是数据库查询中常见的需求,MyBatis本身并不直接支持分页功能,但可以通过插件来实现,从而帮助我们在查询数据库的时候更加方便快捷
引入依赖
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper</artifactId>
<version>5.2.0</version>
</dependency>
在MyBatis-config.xml文件中配置分页插件
MyBatis核心配置文件中,标签的顺序: 重点强调顺序,我被坑过
- properties
- settings
- typeAliases
- typeHandlers
- objectFactory
- objectWrapperFactory
- reflectorFactory
- plugins
- environments
- databaseIdProvider
- mappers
<plugins>
<!--设置分页插件-->
<plugin interceptor="com.github.pagehelper.PageInterceptor"></plugin>
</plugins>
仅MyBatis的测试
引入相关依赖
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.7</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.28</version>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
<!-- Mybatis 分页插件 -->
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper</artifactId>
<version>5.2.0</version>
</dependency>
Mybatis-config.xml完整文件
<?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>
<!--
MyBatis核心配置文件中,标签的顺序:
properties?,settings?,typeAliases?,typeHandlers?,
objectFactory?,objectWrapperFactory?,reflectorFactory?,
plugins?,environments?,databaseIdProvider?,mappers?
-->
<!--引入properties文件-->
<properties resource="jdbc.properties" />
<!--设置类型别名-->
<typeAliases>
<!--
typeAlias:设置某个类型的别名
属性:
type:设置需要设置别名的类型
alias:设置某个类型的别名,若不设置该属性,那么该类型拥有默认的别名,即类名且不区分大小写
-->
<!--<typeAlias type="com.atguigu.mybatis.pojo.User"></typeAlias>-->
<!--以包为单位,将包下所有的类型设置默认的类型别名,即类名且不区分大小写-->
<package name="com.miaow.mybatis.bean"/>
</typeAliases>
<!-- 该死的Mybatis 分页插件还有顺序 导入配置还要按照顺序进行-->
<plugins>
<plugin interceptor="com.github.pagehelper.PageInterceptor">
</plugin>
</plugins>
<!--
environments:配置多个连接数据库的环境
属性:
default:设置默认使用的环境的id
-->
<environments default="development">
<!--
environment:配置某个具体的环境
属性:
id:表示连接数据库的环境的唯一标识,不能重复
-->
<environment id="development">
<!--
transactionManager:设置事务管理方式
属性:
type="JDBC|MANAGED"
JDBC:表示当前环境中,执行SQL时,使用的是JDBC中原生的事务管理方式,事务的提交或回滚需要手动处理
MANAGED:被管理,例如Spring
-->
<transactionManager type="JDBC"/>
<!--
dataSource:配置数据源
属性:
type:设置数据源的类型
type="POOLED|UNPOOLED|JNDI"
POOLED:表示使用数据库连接池缓存数据库连接
UNPOOLED:表示不使用数据库连接池
JNDI:表示使用上下文中的数据源
-->
<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>
<!-- 配置多个数据源 -->
<environment id="test">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/test?serverTimezone=UTC"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
</dataSource>
</environment>
</environments>
<!--引入映射文件-->
<mappers>
<!--xml引入配置文件 -->
<!--<mapper resource="mappers/UserMapper.xml"/>-->
<!--
以包为单位引入映射文件
要求:
1、mapper接口所在的包要和映射文件所在的包一致
2、mapper接口要和映射文件的名字一致
-->
<package name="com.miaow.mybatis.mapper"/>
</mappers>
</configuration>
实体类User
package com.miaow.mybatis.bean;
import java.util.List;
/**
* @author HWZ
* @date 2024年05月07日 22:58
* @description
**/
public class User {
private int id;
private String name;
private String username;
private String sex;
private Book book;
private Integer uid;
private String bookName;
private String cool;
private List<Book> books;
public List<Book> getBooks() {
return books;
}
public void setBooks(List<Book> books) {
this.books = books;
}
// @Override
// public String toString() {
// return "User{" +
// "id=" + id +
// ", name='" + name + '\'' +
// ", username='" + username + '\'' +
// ", sex='" + sex + '\'' +
// ", book=" + book +
// '}';
// }
@Override
public String toString() {
return "User{" +
"id=" + id +
", name='" + name + '\'' +
", username='" + username + '\'' +
", sex='" + sex + '\'' +
", book=" + book +
", uid=" + uid +
", bookName='" + bookName + '\'' +
", cool='" + cool + '\'' +
", books=" + books +
'}';
}
public Integer getUid() {
return uid;
}
public void setUid(Integer uid) {
this.uid = uid;
}
public String getBookName() {
return bookName;
}
public void setBookName(String bookName) {
this.bookName = bookName;
}
public String getCool() {
return cool;
}
public void setCool(String cool) {
this.cool = cool;
}
public Book getBook() {
return book;
}
public void setBook(Book book) {
this.book = book;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public User(int id, String name, String username, String sex) {
this.id = id;
this.name = name;
this.username = username;
this.sex = sex;
}
public User() {
}
}
Mapper接口
@Mapper
public interface UserMapper {
/**
* 查询用户对象
*/
User selectUser(@Param("user") User user);
/**
* 插入用户数据
*/
int insertUser(User user);
/**
* 更新数据
*/
int updateUser(@Param("user") User user);
/**
* 删除用户数据
*/
int deleteUser(int id);
/**
* 批量删除用户数据
*/
int deleteUserBatch(@Param("ids") String ids);
/**
* 查询所有用户数据
*/
List<User> selectAll();
/**
* 查询单条数据,并转化为Map对象数据
*/
Map<String,Object> getUserToMap(@Param("id") int id);
/**
* 查询多条数据斌并转化为Map对象数据
*/
List<Map<String,Object>> get100UserToMap();
/**
* 查询多条数据并转换为Map对象的数据的第二种方式
*/
@MapKey("id")
Map<Integer,User> get100UserToMap2();
/**
* 模糊查询
*/
List<User> selectUserLike(@Param("user") User user);
/**
* 动态设置表名查询数据
*/
List<User> selectUserByTableName(@Param("tableName") String tableName);
User getUserById(int id);
/**
* 分步查询,先不考虑
*/
// User getUserById1(int id);
/**
* 多对一 association
*/
User getUserBookById(int id);
/**
* 一对多 collection
*/
List<User> getDeptByUid(int id);
/**
* 动态插入
*/
int insertUserDynamic(@Param("users") List<User> users);
/**
* 根据传入的条件动态查询
*/
List<User> selectUserByCondition(@Param("user") User user);
/**
* trim用于去掉或添加标签中的内容
*/
List<User> selectUserByConditionTrim(@Param("user") User user);
/**
* choose、when、 otherwise相当于if...else if..else
*/
List<User> selectUserByConditionChoose(@Param("user") User user);
/**
* Mybatis的foreach标签用于循环集合,并生成SQL语句的in子句。
* 实现批量删除
*/
int deleteMoreByArray(@Param("ids") int [] ids);
}
Mapper接口的xml映射文件
<?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="com.miaow.mybatis.mapper.UserMapper">
<!-- 启用二级缓存 -->
<cache/>
<!--
resultMap:设置自定义映射
属性:
id:表示自定义映射的唯一标识
type:查询的数据要映射的实体类的类型
子标签:
id:设置主键的映射关系
result:设置普通字段的映射关系
association:设置多对一的映射关系
collection:设置一对多的映射关系
属性:
property:设置映射关系中实体类中的属性名
column:设置映射关系中表中的字段名
-->
<resultMap id="userMap" type="User">
<!-- 实际山和我们数据库字段别名差不多-->
<id property="id" column="id"></id>
<result property="name" column="name"></result>
<result property="username" column="username"></result>
<result property="sex" column="sex"></result>
<association property="book" javaType="Book">
<id property="uid" column="uid"></id>
<result property="book" column="bookName"></result>
<result property="cool" column="cool"></result>
</association>
</resultMap>
<sql id="baseColum">
id,name,username,sex
</sql>
<resultMap id="deptMap" type="User">
<id property="id" column="id"></id>
<result property="name" column="name"></result>
<result property="username" column="username"></result>
<result property="sex" column="sex"></result>
<collection property="books" ofType="Book">
<result property="uid" column="uid"></result>
<result property="book" column="bookName"></result>
<result property="cool" column="cool"></result>
</collection>
</resultMap>
<select id="getDeptByUid" resultMap="deptMap">
select a.*, b.uid as uid, b.book as bookName, b.cool as cool
from user a
left join book b on a.id = b.uid
where a.id = #{id}
</select>
<!-- <resultMap id="userBookMap" type="User">-->
<!-- <!– 实际山和我们数据库字段别名差不多–>-->
<!-- <id property="id" column="id"></id>-->
<!-- <result property="name" column="name"></result>-->
<!-- <result property="username" column="username"></result>-->
<!-- <result property="sex" column="sex"></result>-->
<!-- <association property="book" select="com.miaow.mybatis.mapper.BookMapper.getBooksByUserUId" column="uid"/>-->
<!--<!– 分步查询 ,再三考虑觉得还是跳过这种方式, –>-->
<!-- </resultMap>-->
<!-- 根据resultMap获取相关数据-->
<select id="getUserById" resultMap="userMap" parameterType="int" useCache="true">
select <include refid="baseColum"></include>
from user
where id = #{id};
</select>
<!-- <select id="getUserById1" resultMap="userBookMap" parameterType="int">-->
<!-- select * from user where id = #{id};-->
<!-- </select>-->
<!-- 管理其他表多对一查询 -->
<select id="getUserBookById" resultMap="userMap" parameterType="int">
select a.*, b.uid as uid, b.book as bookName, b.cool as cool
from user a
left join book b on a.id = b.uid
where a.id = #{id}
</select>
<!-- 插入单条数据
* useGeneratedKeys:设置使用自增的主键
* keyProperty:因为增删改有统一的返回值是受影响的行数,因此只能将获取的自增的主键放在传输的参数user对象的某个属性中
-->
<insert id="insertUser" parameterType="com.miaow.mybatis.bean.User" useGeneratedKeys="true" keyProperty="id">
insert into user
values (#{id}, #{username}, #{name}, #{sex})
</insert>
<!-- 更新数据 -->
<update id="updateUser" parameterType="com.miaow.mybatis.bean.User">
update user
set name = #{user.name}
where id = #{user.id}
</update>
<!-- 删除单条数据-->
<delete id="deleteUser" parameterType="int">
delete
from user
where id = #{id}
</delete>
<!-- 批量删除数据-->
<delete id="deleteUserBatch" parameterType="java.lang.String">
delete
from user
where id in (${ids})
</delete>
<!-- foreach 批量删除数据-->
<!-- <delete id="deleteMoreByArray">-->
<!-- delete from user where-->
<!-- <foreach collection="ids" item="id" separator="or">-->
<!-- id = #{id}-->
<!-- </foreach>-->
<!-- </delete>-->
<!-- 批量删除方式2 -->
<delete id="deleteMoreByArray">
delete from user where id in
<foreach collection="ids" item="id" separator="," open="(" close=")">
#{id}
</foreach>
</delete>
<!-- 根据ID查询相关数据-->
<select id="selectUser" resultType="com.miaow.mybatis.bean.User">
select *
from user
where id = #{user.id}
</select>
<!-- 查询数据库所有数据-->
<select id="selectAll" resultType="com.miaow.mybatis.bean.User">
select *
from user
</select>
<select id="getUserToMap" resultType="java.util.Map" parameterType="int">
select *
from user
where id = #{id};
</select>
<select id="get100UserToMap" resultType="java.util.Map">
select *
from user
limit 100;
</select>
<select id="get100UserToMap2" resultType="java.util.Map">
select *
from user
limit 100;
</select>
<select id="selectUserLike" resultType="com.miaow.mybatis.bean.User"
parameterType="com.miaow.mybatis.bean.User">
select *
from user
where username like "%" #{user.username} "%"
</select>
<!-- 动态设置表名查询数据 -->
<select id="selectUserByTableName" resultType="com.miaow.mybatis.bean.User"
parameterType="java.lang.String">
select *
from ${tableName}
limit 100
</select>
<!-- 实现动态插入-->
<insert id="insertUserDynamic">
insert into user values
<foreach collection="users" item="user" separator=",">
(#{user.id},#{user.username}, #{user.name},#{user.sex})
</foreach>
</insert>
<!--根据条件动态查询-->
<select id="selectUserByCondition" resultType="com.miaow.mybatis.bean.User">
select * from user
<where>
<if test="user.id != null">
id = #{user.id}
</if>
<if test="user.userName != '' and user.userName != null">
and username = #{user.username}
</if>
<if test="user.name != '' and user.name != null">
and name = #{user.name}
</if>
<if test="user.sex != '' and user.sex != null">
and sex = #{user.sex}
</if>
</where>
</select>
<!-- trim
prefix:在trim标签中的内容的前面添加某些内容
prefixOverrides:在trim标签中的内容的前面去掉某些内容
suffix:在trim标签中的内容的后面添加某些内容
suffixOverrides:在trim标签中的内容的后面去掉某些内容
-->
<select id="selectUserByConditionTrim" resultType="com.miaow.mybatis.bean.User">
select * from user
<trim prefix="where" suffixOverrides="and">
<if test="user.id != null">
id = #{user.id}
</if>
<if test="user.userName != '' and user.userName != null">
and username = #{user.username}
</if>
<if test="user.name != '' and user.name != null">
and name = #{user.name}
</if>
<if test="user.sex != '' and user.sex != null">
and sex = #{user.sex}
</if>
</trim>
</select>
<!-- choose、when、 otherwise相当于if...else if..else-->
<select id="selectUserByConditionChoose" resultType="com.miaow.mybatis.bean.User">
select * from user
<where>
<choose>
<when test="user.id != null">
id = #{user.id}
</when>
<when test="user.userName != '' and user.userName != null">
and username = #{user.username}
</when>
<when test="user.name != '' and user.name != null">
and name = #{user.name}
</when>
<when test="user.sex != '' and user.sex != null">
and sex = #{user.sex}
</when>
</choose>
</where>
</select>
</mapper>
测试方法
@Test
public void test17() throws IOException {
InputStream is = Resources.getResourceAsStream("D:\\myProgram\\IDEAProgram\\java-again\\SSM\\src\\main\\resources\\mybatis-config.xml");
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
SqlSession session = sqlSessionFactory.openSession(true);
UserMapper userMapper = session.getMapper(UserMapper.class);
//查询之前,设置分页条件
//显示第1页10条数据
Page<Object> page = PageHelper.startPage(1, 10);
User user = new User();
List<User> users = userMapper.selectAll();
if (users == null || users.size() == 0) {
System.out.println("你查询的表无数据");
return;
}
for (User user1 : users) {
System.out.println(user1);
}
//获取分页
System.out.println("总条数:" + page.getTotal());
System.out.println("总页数:" + page.getPages());
System.out.println("当前页:" + page.getPageNum());
System.out.println("每页显示条数:" + page.getPageSize());
session.close();
}
- pageNum:当前页的页码
- pageSize:每页显示的条数
- size:当前页显示的真实条数
- total:总记录数
- pages:总页数
- prePage:上一页的页码
- nextPage:下一页的页码
- isFirstPage/isLastPage:是否为第一页/最后一页
- hasPreviousPage/hasNextPage:是否存在上一页/下一页
- navigatePages:导航分页的页码数
- navigatepageNums:导航分页的页码,[1,2,3,4,5]
Spring + MyBatis 相对完整的案例
引入依赖
首先,在pom.xml文件中引入MyBatis和分页插件的依赖。
<dependency>
<groupId>org.mybatis.spring</groupId>
<artifactId>mybatis-spring</artifactId>
<version>2.0.6</version>
</dependency>
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper</artifactId>
<version>5.2.0</version>
</dependency>
配置MyBatis分页插件
在在Spring的配置文件中(如applicationContext.xml),配置分页插件。
<bean id="pageHelper" class="com.github.pagehelper.PageInterceptor">
<property name="properties">
<props>
<prop key="helperDialect">mysql</prop>
<prop key="reasonable">true</prop>
<prop key="supportMethodsArguments">true</prop>
<prop key="params">count=countSql</prop>
</props>
</property>
</bean>
配置MyBatis SqlSessionFactory
在Spring的配置文件中,配置MyBatis的SqlSessionFactory,并将分页插件添加到SqlSessionFactory中。
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="plugins">
<array>
<ref bean="pageHelper" />
</array>
</property>
<property name="mapperLocations" value="classpath*:mappers/*.xml" />
</bean>
配置数据源和事务管理
配置数据源和事务管理器。
<bean id="dataSource" class="com.zaxxer.hikari.HikariDataSource">
<property name="driverClassName" value="com.mysql.cj.jdbc.Driver" />
<property name="jdbcUrl" value="jdbc:mysql://localhost:3306/your_database" />
<property name="username" value="your_username" />
<property name="password" value="your_password" />
</bean>
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean>
<tx:annotation-driven transaction-manager="transactionManager" />
创建Mapper接口
定义Mapper接口,并编写查询方法。例如:
@Mapper
public interface UserMapper {
@Select("SELECT * FROM users")
List<User> selectAllUsers();
}
使用分页插件
在Service层或Controller层中使用PageHelper进行分页操作。
@Service
public class UserService {
@Autowired
private UserMapper userMapper;
public PageInfo<User> getUsers(int pageNum, int pageSize) {
PageHelper.startPage(pageNum, pageSize);
List<User> users = userMapper.selectAllUsers();
return new PageInfo<>(users);
}
}
调用分页方法
在Controller中调用分页方法,并返回分页结果。
@RestController
public class UserController {
@Autowired
private UserService userService;
@GetMapping("/users")
public PageInfo<User> getUsers(@RequestParam(defaultValue = "1") int pageNum,
@RequestParam(defaultValue = "10") int pageSize) {
return userService.getUsers(pageNum, pageSize);
}
}
注意博客主要围绕在实例上进行,很多东西都是建立在相关之前的mybatis系列文章的基础上,但为了给新手玩家看到明白,我将上述实例给出了,当然你直接复制粘贴肯定是会报错的,尤其是第一个Mybatis的实例,因为Book类需要你自己创建一个,里边属性值,你看心情给予吧,反正也无伤大雅。
最后补充一下Mybatis分页插件提供的配置属性:
- helperDialect: 指定数据库的方言,如mysql、oracle、postgresql等。插件会根据方言生成相应的分页SQL。
- reasonable: 当该参数设置为true时,如果pageNum<1会查询第一页,如果pageNum>pages会查询最后一页。默认值为false。
- supportMethodsArguments: 支持从方法参数读取分页参数。默认值为false。
- params: 用于配置一些特殊的参数,如count=countSql表示使用count查询时的SQL。
- pageSizeZero: 当该参数设置为true时,如果pageSize=0则查询全部结果。默认值为false
- rowBoundsWithCount: 使用RowBounds分页时是否进行count查询。默认值为false。
- offsetAsPageNum: 使用RowBounds分页时,是否将offset作为pageNum使用。默认值为false。
- pageSizeZero: 当pageSize为0时,返回所有结果。默认值为false。