mybatis-plus

Mybatis-Plus

MyBatis-Plus(简称 MP)是一个MyBatis 的增强工具,在 MyBatis 的基础上只做增强不做改变,为简化开发、提高效率而生。其突出的特性如下:

  • 无侵入:只做增强不做改变,引入它不会对现有工程产生影响,如丝般顺滑
  • 强大的 CRUD 操作:内置通用 Mapper、通用 Service,提供了大量的通用的CRUD方法,因此可以省去大量手写sql的语句的工作。
  • 条件构造器:提供了强大的条件构造器,可以构造各种复杂的查询条件,以应对各种复杂查询。
  • 内置分页插件:配置好插件之后,写分页等同于普通 List 查询,无需关注分页逻辑。

Mybatis Plus与SpringBoot的集成

引入Maven 依赖

提前创建好一个SpringBoot项目,然后在项目中引入MyBatis Plus依赖

<!--springboot2-->
<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-boot-starter</artifactId>
    <version>3.5.6</version>
</dependency>

<!--springboot3-->
<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-spring-boot3-starter</artifactId>
    <version>3.5.7</version>
</dependency>

配置application.yml文件

#springboot整合mybatisPlus
mybatis-plus:
  #配置别名包
  #MyBatis 在启动时会扫描该包下的所有类,并为其中的每个类创建一个别名。例如,如果我们有一个 com.example.model.User 的     #类,MyBatis 会为其自动创建一个别名 User。
  #用于自动扫描指定包路径下的类,并为这些类创建别名
  type-aliases-package: com.chs.pojo  
  #加载指定位置的映射文件
  mapper-locations: classpath:/mapper/*.xml
  configuration:
    #开启驼峰映射规则
    map-underscore-to-camel-case: true
    #添加操作日志
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

实体类配置

@Data
//表中的user表数据于当前User类绑定
@TableName("user")
public class User {
    //主键自增,并于数据库中id字段绑定
    @TableId(value = "id", type = IdType.AUTO)
    private Long id;

    @TableField("name")
    private String name;

    @TableField("age")
    private Integer age;
    
    //当数据库字段名和实体类数据名一致时,可以不用写@TableField(value = "age")。
    @TableField("email")
    private String email;
}

注解知识点

实体类中的三个注解的含义如下

  • @TableName:表名注解,用于标识实体类所对应的表

    • value:用于声明表名
  • @TableId:主键注解,用于标识主键字段

    • value:用于声明主键的字段名
    • type:用于声明主键的生成策略,常用的策略有AUTOASSIGN_UUIDINPUT等等
  • @TableField:普通字段注解,用于标识属性所对应的表字段

    • value:用于声明普通字段的字段名

通用Mapper

通用Mapper提供了通用的CRUD方法,使用它可以省去大量编写简单重复的SQL语句的工作,具体用法如下

创建Mapper接口

创建UserMapper接口,并继承由Mybatis Plus提供的BaseMapper<T>接口,如下

@Mapper
public interface UserMapper extends BaseMapper<User> {
}

知识点:若Mapper接口过多,可不用逐一配置@Mapper注解,而使用@MapperScan注解指定包扫描路径进行统一管理,例如

@SpringBootApplication
@MapperScan("com.atguigu.hellomp.mapper")
public class HelloMpApplication {
    public static void main(String[] args) {
        SpringApplication.run(HelloMpApplication.class, args);
    }
}

常用使用方法mapper层

添加数据

//【添加数据:(增)】
int insert(T entity);              // 插入一条记录
List<BatchResult> insert(Collection<T> entityList); //批量插入多条数据

注:
    T         表示任意实体类型
    entity    表示实体对象

insert 后主键会自动 set 到实体的 ID 字段 所以后面你只需要 getld() 就好

删除数据

//【删除数据:(删)】
int deleteById(Serializable id);    // 根据主键 ID 删除

int deleteByMap(@Param(Constants.COLUMN_MAP) Map<String, Object> columnMap);  // 根据 map 定义字段的条件删除

int delete(@Param(Constants.WRAPPER) Wrapper<T> wrapper); // 根据实体类定义的 条件删除对象

int deleteBatchIds(@Param(Constants.COLLECTION) Collection<? extends Serializable> idList); // 进行批量删除

注:
    id        表示 主键 ID
    columnMap 表示表字段的 map 对象
    wrapper   表示实体对象封装操作类,可以为 null。
    idList    表示 主键 ID 集合(列表、数组),不能为 null 或 empty

修改数据

//【修改数据:(改)】
int updateById(@Param(Constants.ENTITY) T entity); // 根据 ID 修改实体对象。

int update(@Param(Constants.ENTITY) T entity, @Param(Constants.WRAPPER) Wrapper<T> updateWrapper); // 根据 updateWrapper 条件修改实体对象

注:
    update 中的 entity 为 set 条件,可以为 null。
    updateWrapper 表示实体对象封装操作类(可以为 null,里面的 entity 用于生成 where 语句)

查询数据

//【查询数据:(查)】
T selectById(Serializable id); // 根据 主键 ID 查询数据

List<T> selectBatchIds(@Param(Constants.COLLECTION) Collection<? extends Serializable> idList); // 进行批量查询

List<T> selectByMap(@Param(Constants.COLUMN_MAP) Map<String, Object> columnMap); // 根据表字段条件查询

T selectOne(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper); // 根据实体类封装对象 查询一条记录

Integer selectCount(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper); // 查询记录的总条数

List<T> selectList(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper); // 查询所有记录(返回 entity 集合)

List<Map<String, Object>> selectMaps(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper); // 查询所有记录(返回 map 集合)

List<Object> selectObjs(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper); // 查询所有记录(但只保存第一个字段的值)

<E extends IPage<T>> E selectPage(E page, @Param(Constants.WRAPPER) Wrapper<T> queryWrapper); // 查询所有记录(返回 entity 集合),分页

<E extends IPage<Map<String, Object>>> E selectMapsPage(E page, @Param(Constants.WRAPPER) Wrapper<T> queryWrapper); // 查询所有记录(返回 map 集合),分页

注:
    queryWrapper 表示实体对象封装操作类(可以为 null)
    page 表示分页查询条件

测试常用方法Mapper

创建userMapperTest测试类型,内容如下

@SpringBootTest
class UserMapperTest {
    @Autowired
    private UserMapper userMapper;
    @Test
    public void testSelectList() {
        //获取所有用户
        List<User> users = userMapper.selectList(null);
        users.forEach(System.out::println);
    }

    @Test
    public void testSelectById() {
        //根据id获取用户
        User user = userMapper.selectById(1);
        System.out.println(user);
    }

    @Test
    //插入用户
    public void testInsert() {
        User user = new User();
        user.setName("zhangsan");
        user.setAge(11);
        user.setEmail("test@test.com");
        userMapper.insert(user);
    }

    @Test
    //根据id修改用户
    public void testUpdateById() {
        User user = userMapper.selectById(1);
        user.setName("xiaoming");
        userMapper.updateById(user);
    }
    
    @Test
    //根据id删除用户
    public void testDeleteById() {
        userMapper.deleteById(1);
    }
}

通用Service

通用Service进一步封装了通用Mapper的CRUD方法,并提供了例如saveOrUpdatesaveBatch等高级方法。

创建Service接口

创建UserService,内容如下

public interface UserService extends IService<User> {
}

创建Service实现类

创建UserServiceImpl,内容如下

@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {
}

常用使用方法Service层

添加数据

//【添加数据:(增)】
default boolean save(T entity); // 调用 BaseMapper 的 insert 方法,用于添加一条数据。

boolean saveBatch(Collection<T> entityList, int batchSize); // 批量插入数据

注:
entityList 表示实体对象集合 
batchSize 表示一次批量插入的数据量,默认为 1000

修改或添加数据

//【添加或修改数据:(增或改)】
boolean saveOrUpdate(T entity); // id 若存在,则修改, id 不存在则新增数据

default boolean saveOrUpdate(T entity, Wrapper<T> updateWrapper); // 先根据条件尝试更新,然后再执行 saveOrUpdate 操作

boolean saveOrUpdateBatch(Collection<T> entityList, int batchSize); // 批量插入并修改数据 

删除数据

//【删除数据:(删)】
default boolean removeById(Serializable id); // 调用 BaseMapper 的 deleteById 方法,根据 id 删除数据。

default boolean removeByMap(Map<String, Object> columnMap); // 调用 BaseMapper 的 deleteByMap 方法,根据 map 定义字段的条件删除

default boolean remove(Wrapper<T> queryWrapper); // 调用 BaseMapper 的 delete 方法,根据实体类定义的 条件删除对象。

default boolean removeByIds(Collection<? extends Serializable> idList); // 用 BaseMapper 的 deleteBatchIds 方法, 进行批量删除。

修改数据

//【修改数据:(改)】
default boolean updateById(T entity); // 调用 BaseMapper 的 updateById 方法,根据 ID 选择修改。

default boolean update(T entity, Wrapper<T> updateWrapper); // 调用 BaseMapper 的 update 方法,根据 updateWrapper 条件修改实体对象。

boolean updateBatchById(Collection<T> entityList, int batchSize); // 批量更新数据

查询数据

//【查找数据:(查)】
default T getById(Serializable id); // 调用 BaseMapper 的 selectById 方法,根据 主键 ID 返回数据。

default List<T> listByIds(Collection<? extends Serializable> idList); // 调用 BaseMapper 的 selectBatchIds 方法,批量查询数据。

default List<T> listByMap(Map<String, Object> columnMap); // 调用 BaseMapper 的 selectByMap 方法,根据表字段条件查询。

default T getOne(Wrapper<T> queryWrapper); // 返回一条记录(实体类保存)。

Map<String, Object> getMap(Wrapper<T> queryWrapper); // 返回一条记录(map 保存)。

default int count(Wrapper<T> queryWrapper); // 根据条件返回 记录数。

default List<T> list(); // 返回所有数据。

default List<T> list(Wrapper<T> queryWrapper); // 调用 BaseMapper 的 selectList 方法,查询所有记录(返回 entity 集合)。

default List<Map<String, Object>> listMaps(Wrapper<T> queryWrapper); // 调用 BaseMapper 的 selectMaps 方法,查询所有记录(返回 map 集合)。

default List<Object> listObjs(); // 返回全部记录,但只返回第一个字段的值。

default <E extends IPage<T>> E page(E page, Wrapper<T> queryWrapper); // 调用 BaseMapper 的 selectPage 方法,分页查询。

default <E extends IPage<Map<String, Object>>> E pageMaps(E page, Wrapper<T> queryWrapper); // 调用BaseMapper 的 selectMapsPage 方法,分页查询。

注:
    get 用于返回一条记录。
    list 用于返回多条记录。
    count 用于返回记录总数。
    page 用于分页查询。
     
    
【链式调用:】
    default QueryChainWrapper<T> query(); // 普通链式查询
    default LambdaQueryChainWrapper<T> lambdaQuery(); // 支持 Lambda 表达式的修改
    default UpdateChainWrapper<T> update(); // 普通链式修改
    default LambdaUpdateChainWrapper<T> lambdaUpdate(); // 支持 Lambda 表达式的修改
注:
    query 表示查询
    update 表示修改
    Lambda 表示内部支持 Lambda 写法。
形如:
    query().eq("column", value).one();
    lambdaQuery().eq(Entity::getId, value).list();
    update().eq("column", value).remove();
    lambdaUpdate().eq(Entity::getId, value).update(entity);

测试使用方法Service

创建UserServiceImplTest测试类,内容如下

@SpringBootTest
class UserServiceImplTest {
    @Autowired
    private UserService userService;
    @Test
    public void testSaveOrUpdate() {
        //根据id查询用户
        User user1 = userService.getById(2);
        user1.setName("xiaohu");
        User user2 = new User();
        user2.setName("lisi");
        user2.setAge(27);
        user2.setEmail("lisi@email.com");
        //保存或更新用户
        userService.saveOrUpdate(user1);
        userService.saveOrUpdate(user2);
    }
    @Test
    public void testSaveBatch() {
        User user1 = new User();
        user1.setName("dongdong");
        user1.setAge(49);
        user1.setEmail("dongdong@email.com");

        User user2 = new User();
        user2.setName("nannan");
        user2.setAge(29);
        user2.setEmail("nannan@email.com");

        List<User> users = List.of(user1, user2);
        //批量插入用户
        userService.saveBatch(users);
    }
}

条件构造器

在 MyBatis-Plus 中,Wrapper 类是构建查询和更新条件的核心工具。

  • QueryWrapper:专门用于构造查询条件,支持基本的等于(eq)、不等于(ne)、大于(gt)、小于(lt)等各种常见操作。它允许你以链式调用的方式添加多个查询条件,并且可以组合使用 andor 逻辑。

  • UpdateWrapper:用于构造更新条件,可以在更新数据时指定条件。与 QueryWrapper 类似,它也支持链式调用和逻辑组合。使用 UpdateWrapper 可以在不创建实体对象的情况下,直接设置更新字段和条件。

  • LambdaQueryWrapper:这是一个基于 Lambda 表达式的查询条件构造器,它通过 Lambda 表达式来引用实体类的属性,从而避免了硬编码字段名。这种方式提高了代码的可读性和可维护性,尤其是在字段名可能发生变化的情况下。

  • LambdaUpdateWrapper:类似于 LambdaQueryWrapper,LambdaUpdateWrapper 是基于 Lambda 表达式的更新条件构造器。它允许你使用 Lambda 表达式来指定更新字段和条件,同样避免了硬编码字段名的问题。

常用条件

比较大小

//【比较大小: ( =, <>, >, >=, <, <= )】
eq(R column, Object val); // 等价于 =
eq(condition...,R column, object val) //当条件满足为true,拼接后面where
ne(R column, Object val); // 等价于 <>
gt(R column, Object val); // 等价于 >
ge(R column, Object val); // 等价于 >=
lt(R column, Object val); // 等价于 <
le(R column, Object val); // 等价于 <=

//例:
QueryWrapper queryWrapper = new QueryWrapper();
queryWrapper.eq("name", "chs") ---> name = 'chs'

范围

//【范围:(between、not between、in、not in)】
between(R column, Object val1, Object val2); // 等价于 between a and b
notBetween(R column, Object val1, Object val2); // 等价于 not between a and b


in(R column, Object... values); // 等价于 字段 IN (v0, v1, ...)
notIn(R column, Object... values); // 等价于 字段 NOT IN (v0, v1, ...)


inSql(R column, Object... values); // 等价于 字段 IN (sql 语句),
//例: inSql("id", "select id from table where id < 3") ---> id in (select id from table where id < 3)
notInSql(R column, Object... values); // 等价于 字段 NOT IN (sql 语句)

模糊匹配

//【模糊匹配:(like)】
like(R column, Object val); // 等价于 LIKE '%值%'

notLike(R column, Object val); // 等价于 NOT LIKE '%值%'

likeLeft(R column, Object val); // 等价于 LIKE '%值'

likeRight(R column, Object val); // 等价于 LIKE '值%'

空值比较

【空值比较:(isNull、isNotNull)】
isNull(R column); // 等价于 IS NULL

isNotNull(R column); // 等价于 IS NOT NULL

分组排序

//【分组、排序:(group、having、order)】
groupBy(R... columns); // 等价于 GROUP BY 字段, ...

orderByAsc(R... columns); // 等价于 ORDER BY 字段, ... ASC(升序--小到大)

orderByDesc(R... columns); // 等价于 ORDER BY 字段, ... DESC(降序--大到小)

having(String sqlHaving, Object... params); // 等价于 HAVING ( sql语句 )

拼接、嵌套sql

//【拼接、嵌套 sql:(or、and、nested、apply)】
or(); // 等价于 a or b, 例:eq("id",1).or().eq("name","chs") ---> id = 1 or name = 'chs'

or(Consumer<Param> consumer); // 等价于 or(a or/and b),or 嵌套。
//例: or(i -> i.eq("name", "李白").ne("status", "活着")) ---> or (name = '李白' and status <> '活着')

and(Consumer<Param> consumer); // 等价于 and(a or/and b),and 嵌套。
//例: and(i -> i.eq("name", "李白").ne("status", "活着")) ---> and (name = '李白' and status <> '活着')

nested(Consumer<Param> consumer); // 等价于 (a or/and b),普通嵌套。

apply(String applySql, Object... params); // 拼接sql(若不使用 params 参数,可能存在 sql 注入),
//例: apply("date_format(dateColumn,'%Y-%m-%d') = {0}", "2008-08-08") ---> date_format(dateColumn,'%Y-%m-%d') = '2008-08-08'")

last(String lastSql); // 无视优化规则直接拼接到 sql 的最后,可能存若在 sql 注入。

exists(String existsSql); // 拼接 exists 语句。例: exists("select id from table where age = 1") 

条件

【QueryWrapper 条件:】
select(String... sqlSelect); // 用于定义需要返回的字段。
//例: select("id", "name", "age") ---> select id, name, age

select(Predicate<TableFieldInfo> predicate); // Lambda 表达式,过滤需要的字段。

lambda(); // 返回一个 LambdaQueryWrapper
    

【UpdateWrapper 条件:】
set(String column, Object val); // 用于设置 set 字段值。例: set("name", null) ---> set name = null

etSql(String sql); // 用于设置 set 字段值。例: setSql("name = '老李头'") ---> set name = '老李头'

lambda(); // 返回一个 LambdaUpdateWrapper```

例:QueryWrapper

@Test
public void testQueryWrapper() {
    // Step1:创建一个 QueryWrapper 对象
    QueryWrapper<User> queryWrapper = new QueryWrapper<>();

    // Step2: 构造查询条件
    queryWrapper
            .select("id", "name", "age")   //指定需要返回的字段
            .eq("age", 20)
            .like("name", "j");

    // Step3:执行查询
    userService
            .list(queryWrapper)
            .forEach(System.out::println);
}

测试wrapper

@SpringBootTest
public class WrapperTest {
    @Autowired
    private UserService userService;
    //查询条件
    @Test
    public void testQueryWrapper() {

        //查询name=Tom的所有用户
        QueryWrapper<User> queryWrapper1 = new QueryWrapper<>();
        queryWrapper1.eq("name", "Tom");

        //查询邮箱域名为baomidou.com的所有用户
        QueryWrapper<User> queryWrapper2 = new QueryWrapper<>();
        queryWrapper2.like("email", "baomidou.com");

        //查询所有用户信息并按照age字段降序排序
        QueryWrapper<User> queryWrapper3 = new QueryWrapper<>();
        queryWrapper3.orderByDesc("age");
        
        //查询age介于[20,30]的所有用户
        QueryWrapper<User> queryWrapper4 = new QueryWrapper<>();
        queryWrapper4.between("age", 20, 30);
        
        //查询age小于20或大于30的用户
        QueryWrapper<User> queryWrapper5 = new QueryWrapper<>();
        queryWrapper5.lt("age", 20).or().gt("age", 30);

        //邮箱域名为baomidou.com且年龄小于30或大于40且的用户
        QueryWrapper<User> queryWrapper6 = new QueryWrapper<>();
        queryWrapper6.like("email", "baomidou.com").and(wrapper -> wrapper.lt("age", 30).or().gt("age", 40));
        
        List<User> list = userService.list(queryWrapper6);
        list.forEach(System.out::println);
    }
    
    //更新条件
    @Test
    public void testUpdateWrapper() {

        //将name=Tom的用户的email改为Tom@baobidou.com
        UpdateWrapper<User> updateWrapper = new UpdateWrapper<>();
        updateWrapper.eq("name", "Tom");
        updateWrapper.set("email", "Tom@baobidou.com");

        userService.update(updateWrapper);
    }
}

测试LambdaWrapper

上述的QueryWrapperUpdateWrapper均有一个Lambda版本,也就是LambdaQueryWrapperLambdaUpdateWrapperLambda版本的优势在于,可以省去字段名的硬编码。

@SpringBootTest
public class LambdaWrapperTest {

    @Autowired
    private UserService userService;
    
  	//查询条件
    @Test
    public void testLambdaQueryWrapper() {
        //查询name=Tom的所有用户
        LambdaQueryWrapper<User> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(User::getName, "Tom");

        List<User> list = userService.list(lambdaQueryWrapper);
        list.forEach(System.out::println);

    }
 	//更新条件
    @Test
    public void testLambdaUpdateWrapper() {
        //将name=Tom的用户的邮箱改为Tom@tom.com
        LambdaUpdateWrapper<User> lambdaUpdateWrapper = new LambdaUpdateWrapper<>();
        lambdaUpdateWrapper.eq(User::getName, "Tom");
        lambdaUpdateWrapper.set(User::getEmail, "Tom@Tom.com");

        userService.update(lambdaUpdateWrapper);
    }
}

逻辑删除

逻辑删除,可以方便地实现对数据库记录的逻辑删除而不是物理删除。逻辑删除是指通过更改记录的状态或添加标记字段来模拟删除操作,从而保留了删除前的数据,便于后续的数据分析和恢复。

  • 物理删除:真实删除,将对应数据从数据库中删除,之后查询不到此条被删除的数据
  • 逻辑删除:假删除,将对应数据中代表是否被删除字段的状态修改为“被删除状态”,之后在数据库中仍旧能看到此条数据记录

数据库和实体类添加逻辑删除字段

表添加逻辑删除字段,可以是一个布尔类型、整数类型或枚举类型。

ALTER TABLE USER ADD deleted INT DEFAULT 0 ;  # int 类型 1 逻辑删除 0 未逻辑删除

实体类添加属性

@Data
public class User {
    private Integer id;
    private String name;
    private Integer age;
    private String email;
    
    private Integer deleted; //逻辑删除字段
}

指定逻辑删除字段和属性值

单一指定

@Data
public class User {
    private Integer id;
    private String name;
    private Integer age;
    private String email;
    @TableLogic
    //逻辑删除字段 int mybatis-plus下,默认 逻辑删除值为1 未逻辑删除 0 
    private Integer deleted;
}

全局配置

mybatis-plus:
  global-config:
    db-config:
      logic-delete-field: deleted # 全局逻辑删除的实体字段名(since 3.3.0,配置后可以忽略不配置步骤2)
      logic-delete-value: 1 # 逻辑已删除值(默认为 1)
      logic-not-delete-value: 0 # 逻辑未删除值(默认为 0)

注意:==>逻辑删除以后,没有真正的删除语句,删除改为修改语句!

自动填充字段

MyBatis-Plus 提供了一个便捷的自动填充功能,用于在插入或更新数据时自动填充某些字段,如创建时间、更新时间等。以下是如何使用这一功能的详细说明。

定义实体类

在实体类中,你需要使用 @TableField 注解来标记哪些字段需要自动填充,并指定填充的策略。

public class User {
    @TableField(fill = FieldFill.INSERT)
    private String createTime;

    @TableField(fill = FieldFill.UPDATE)
    private String updateTime1;
    
    @TableField(value = "update_time", fill = FieldFill.INSERT_UPDATE)
    private Date updateTime2;

    // 其他字段...
}

实现 MetaObjectHandler

创建一个类来实现 MetaObjectHandler 接口,并重写 insertFillupdateFill 方法。

@Slf4j
@Component
public class MyMetaObjectHandler implements MetaObjectHandler {
    /**
     * 自定义插入时填充规则
     */
    @Override
    public void insertFill(MetaObject metaObject) {
        log.info("开始插入填充...");
        this.strictInsertFill(metaObject, "createTime", LocalDateTime.class, LocalDateTime.now());
        this.strictUpdateFill(metaObject, "updateTime2", LocalDateTime.class, LocalDateTime.now());
    }
 	/**
     * 自定义更新时填充规则
     */
    @Override
    public void updateFill(MetaObject metaObject) {
        log.info("开始更新填充...");
        this.strictUpdateFill(metaObject, "updateTime1", LocalDateTime.class, LocalDateTime.now());
    }
}

注意:确保你的 MyMetaObjectHandler 类被 Spring 管理,可以通过 @Component@Bean 注解来实现。

其他注意事项
字段类型: 确保数据库中的 createTime 和 updateTime 字段类型与 Java 实体类中的类型相匹配(通常是 DATETIME 类型)。
时间格式: 如果需要统一时间格式,可以在配置文件中设置 Spring Boot 的全局时间格式,或使用 @JsonFormat 注解指定序列化时的格式。

spring:
  jackson:
    date-format: yyyy-MM-dd HH:mm:ss
    time-zone: GMT+8

分页插件

分页查询是一个很常见的需求,故Mybatis-Plus提供了一个分页插件,使用它可以十分方便的完成分页查询。下面介绍Mybatis-Plus分页插件的用法,详细信息可参考[官方文档](分页插件 | MyBatis-Plus (baomidou.com))。

配置分页插件

创建com.atguigu.hellomp.config.MPConfiguration配置类,增加如下内容

@Configuration
@MapperScan("scan.your.mapper.package")
public class MybatisPlusConfig {

    /**
     * 添加分页插件
     */
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
        // 如果配置多个插件, 切记分页最后添加
        // 如果有多数据源可以不配具体类型, 否则都建议配上具体的 DbType
        return interceptor;
    }
}

分页插件使用说明

Page 类

Page 类继承了 IPage 类,实现了简单分页模型。如果你需要实现自己的分页模型,可以继承 Page 类或实现 IPage 类。

属性名 类型 默认值 描述
records List emptyList 查询数据列表
total Long 0 查询列表总记录数
size Long 10 每页显示条数,默认 10
current Long 1 当前页
orders List emptyList 排序字段信息
optimizeCountSql boolean true 自动优化 COUNT SQL
optimizeJoinOfCountSql boolean true 自动优化 COUNT SQL 是否把 join 查询部分移除
searchCount boolean true 是否进行 count 查询
maxLimit Long 单页分页条数限制
countId String XML 自定义 count 查询的 statementId

分页对象既作为分页查询的参数,也作为分页查询的返回结果,当作为查询参数时,通常只需提供currentsize属性,如下

IPage<T> page = new Page<>(current, size);

注:IPage为分页接口,PageIPage接口的一个实现类。

分页查询

Mybatis Plus的BaseMapperServiceImpl均提供了常用的分页查询的方法,例如:

BaseMapper的分页查询:

IPage<T> selectPage(IPage<T> page,Wrapper<T> queryWrapper);

ServiceImpl的分页查询:

// 无条件分页查询
IPage<T> page(IPage<T> page);
// 条件分页查询
IPage<T> page(IPage<T> page, Wrapper<T> queryWrapper);

自定义Mapper

对于自定义SQL,也可以十分方便的完成分页查询,如下

Mapper接口:

IPage<UserVo> selectPageVo(IPage<?> page, Integer state);

Mapper.xml

<select id="selectPageVo" resultType="xxx.xxx.xxx.UserVo">
    SELECT id,name FROM user WHERE state=#{state}
</select>

注意Mapper.xml中的SQL只需实现查询list的逻辑即可,无需关注分页的逻辑。

分页查询测试

@SpringBootTest
public class PageTest {

    @Autowired
    private UserService userService;

    @Autowired
    private UserMapper userMapper;

    //通用Service分页查询
    @Test
    public void testPageService() {
        Page<User> page = new Page<>(2, 3);
        Page<User> userPage = userService.page(page);
        userPage.getRecords().forEach(System.out::println);
    }

    //通用Mapper分页查询
    @Test
    public void testPageMapper() {
        IPage<User> page = new Page<>(2, 3);
        IPage<User> userPage = userMapper.selectPage(page, null);
        userPage.getRecords().forEach(System.out::println);
    }
//---------------------------------------------------------------------------
    //自定义SQL分页查询
    @Test
    public void testCustomMapper() {
        IPage<User> page = new Page<>(2, 3);
        IPage<User> userPage = userMapper.selectUserPage(page);
        userPage.getRecords().forEach(System.out::println);
    }
}

在UserMapper中声明分页查询方法如下

IPage<User> selectUserPage(IPage<User> page);

创建resources/mapper/UserMapper.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.atguigu.hellomp.mapper.UserMapper">
    <select id="selectUserPage" resultType="com.atguigu.hellomp.entity.User">
        select *
        from user
    </select>
</mapper>

注意

Mybatis-Plus中Mapper.xml文件路径默认为:classpath*:/mapper/**/*.xml,可在application.yml中配置以下参数进行修改

mybatis-plus:
  mapper-locations: classpath*:/mapper/**/*.xml

MyBatisX插件

MyBatis Plus提供了一个IDEA插件——MybatisX,使用它可根据数据库快速生成EntityMapperMapper.xmlServiceServiceImpl等代码,使用户更专注于业务。

安装插件

在IDEA插件市场搜索MyBatisX,进行在线安装

配置数据库连接

在IDEA中配置数据库连接

IDEA数据连接

生成代码

首先将之前编写的UserUserMapperUserServcieUserServiceImpl全部删除,然后按照下图指示使用插件生成代码

配置实体类相关信息

代码生成-实体类配置

配置代码模版信息

代码生成模版配置

点击Finish然后查看生成的代码。

posted @ 2024-09-25 09:43  CH_song  阅读(6)  评论(0编辑  收藏  举报