Mybatis Plus之内置Mapper实践

MyBatis Plus,作为对MyBatis的进一步增强,大大简化了我们的开发流程,提高了开发速度

配置

由于Mybatis Plus是建立在Mybatis之上的,所以其已经依赖了Mybatis,故我们无需在项目中显式地重复添加Mybatis依赖。直接在POM文件中Mybatis Plus依赖即可

<!--Mybatis Plus-->
<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-boot-starter</artifactId>
    <version>3.4.1</version>
</dependency>

Mapper CRUD操作

在Mybatis下,需要我们自行编写Mapper接口文件、提供sql的的xml文件。众所周知,这些CRUD的接口写起来不仅繁琐还容易出错,为此在Mybatis Plus中提供了内置的Mapper。高效实现CRUD操作

-- 创建数据表
create table t_people_info (
 id int not null auto_increment comment 'ID',
 name varchar(255) null comment '姓名',
 sex varchar(255) null comment '性别',
 primary key (id)
) comment '信息表';

POJO类定义如下,这里展示了@TableName、@TableField注解的用法

import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;

@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
@TableName("t_people_info")     // 指定数据库的表名
public class People {
    /**
     * ID
     */
    private int id;

    /**
     * 姓名
     */
    @TableField("name")     // 该属性在数据表中对应的字段名
    private String username;

    /**
     * 性别
     */
    private String sex;

    /**
     * 职业
     */
    @TableField(exist = false)  // 该属性在数据表中不存在
    private String job;
}

而Mapper接口文件只需继承BaseMapper即可获得Mybatis Plus提供的基本的CRUD功能,无需我们定义接口及相关的SQL。当然如果需要复杂的操作直接在PeopleMapper接口中继续添加即可

import com.baomidou.mybatisplus.core.mapper.BaseMapper;

public interface PeopleMapper extends BaseMapper<People> {

}

public class ProperService {

    @Autowired
    private PeopleMapper peopleMapper;
    
    public void testInsert() {
        List<People> list = new LinkedList<>();
        list.add( People.builder().username("小明").build() );
        list.add( People.builder().id(10).username("老王").sex("男").build() );
        list.add( People.builder().id(11).username("老张").sex("女").build() );
        list.add( People.builder().id(12).sex("女").build() );

        for (People people : list) {
            peopleMapper.insert(people);
        }
    }

}

根据ID删除及批量操作,方式如下

/**
 * 根据ID删除
 */
public void testDeleteById() {
    peopleMapper.deleteById(10);
}

/**
 *  根据ID批量删除
 */
public void testDeleteByIds() {
    List ids = new LinkedList();
    ids.add(11);
    ids.add(12);
    peopleMapper.deleteBatchIds( ids );
}

与此同时,也支持基于条件的删除

/**
 * 根据条件删除
 */
public void testDeleteByParam1() {
    // 表字段map
    Map map = new HashMap();
    // Note:这里设置条件应使用数据表的字段名,而不是Java类的属性名
    map.put("name", "匿名用户");
    map.put("sex", "男");

    // 多个条件为and的关系
    int num = peopleMapper.deleteByMap(map);
    System.out.println("delete num : " + num);
}

/**
 * 根据条件删除
 */
public void testDeleteByParam2() {
    // Note:此时其实隐含了 id为null 的条件
    People people = People.builder()
            .username("翠花")
            .sex("女")
            .build();
    // 多个条件为and的关系
    QueryWrapper<People> wrapper = new QueryWrapper<>(people);

    int num = peopleMapper.delete( wrapper );
    System.out.println("delete num : " + num);
}

同理对于更新操作,支持基于ID的操作方式

/**
 * 根据ID更新
 */
public void testUpdateById() {
    People people = People.builder()
            .id(3)
            .username("孙尚香")
            .build();

    peopleMapper.updateById(people);
}

上述更新语句执行后会发现,id为3的记录,对于name字段确实被更新为 "孙尚香" 了,但是如果sex字段并不会被更新为 NULL。这是因为@TableField注解的updateStrategy属性默认为NOT_NULL所导致的。该属性常用的值及释义如下所示

  • NOT_NULL:要求新值非NULL
  • NOT_EMPTY:要求新值非NULL、非空字符串
  • IGNORED:新值可以为NULL、空字符串

故我们在sex属性上使用@TableField注解,并把updateStrategy设置为FieldStrategy.IGNORED后,上述测试代码对sex字段的更新才会生效

/**
 * 性别
 */
@TableField(updateStrategy = FieldStrategy.IGNORED)
private String sex;

与此同时,也支持基于条件的更新。而且可以看到在基于ID的更新方式中,需要修改@TableField注解的updateStrategy属性,来保证可以更新为NULL、空字符串。显然非常麻烦,而且容易出错。而通过updateWrapper的set方法来设置新值,显式地设置NULL值就非常直观了,不容易出错

/**
 * 根据条件更新
 */
public void testUpdateByParam() {
    
    UpdateWrapper<People> updateWrapper = new UpdateWrapper<>();
    // Note:这里应使用数据表的字段名,而不是Java类的属性名
    
    // where 条件:id 大于 50
    updateWrapper.gt("id",50);
    
    // set 新值:sex 更新为 男
    updateWrapper.set("sex","男");
    // set 新值:name 更新为 NULL   
    updateWrapper.set("name","null");
    
    // 多个条件为and的关系
    peopleMapper.update(null, updateWrapper);
}

根据ID查询及批量操作,方式如下

/**
 * 根据ID查询
 */
public void testSelectById() {
    People people = peopleMapper.selectById(1);
    System.out.println("people: " + people);
}

/**
 * 根据ID批量查询
 */
public void testSelectByIds() {
    List list = new LinkedList();
    list.add(1);
    list.add(2);
    list.add(3);
    List<People> peopleList = peopleMapper.selectBatchIds(list);

    peopleList.forEach(System.out::println);
}

与此同时,也支持基于条件的查询。其中查询条件为空,则查询全部

/**
 * 根据条件查询。其中查询条件为空,则查询全部
 */
public void testSelectAll() {
    List<People> list = peopleMapper.selectList(null);
    list.forEach( System.out::println );
}

/**
 * 根据条件查询
 */
public void testSelectByParam1() {
    QueryWrapper<People> queryWrapper = new QueryWrapper<>();
    // Note:这里设置条件应使用数据表的字段名,而不是Java类的属性名
    // 条件:性别为男
    queryWrapper.eq("sex", "男");
    // 条件:id 小于等于 100
    queryWrapper.le("id", 50);
    // 多个条件为and的关系
    List<People> list = peopleMapper.selectList(queryWrapper);
    list.forEach(System.out::println);
}

/**
 * 根据条件查询
 */
public void testSelectByParam2() {
    // 表字段map
    Map<String, Object> map = new HashMap<>();
    map.put("sex", "女");
    // Note:这里设置条件应使用数据表的字段名,而不是Java类的属性名
    map.put("name", "佳丽");
    // 多个条件为and的关系
    List<People> list = peopleMapper.selectByMap(map);
    list.forEach(System.out::println);
}

有时候我们还需要进行分页查询,在Mybatis Plus下也是非常方便的,只需配置下分页插件即可

@Configuration
public class MybatisPlusConfig {

    /**
     * Mybatis Plus 分页插件
     * @return
     */
    @Bean
    public MybatisPlusInterceptor innerInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
        return interceptor;
    }
}

关于分页查询的操作方式如下所示:

/**
 * 分页查询
 */
public void testSelectByPage() {
    // 查询条件
    QueryWrapper<People> queryWrapper = new QueryWrapper<>();
    // Note:这里设置条件应使用数据表的字段名,而不是Java类的属性名
    // 条件:id 大于 2
    queryWrapper.gt("id", 2);
    // 条件:name字段 (右)模糊匹配 "张%"
    queryWrapper.likeRight("name", "张");
    // 分页参数: 页码:2, 单页大小:10
    Page<People> page = new Page<>(2,10);
    // 分页查询, 多个条件为and的关系
    Page<People> result = peopleMapper.selectPage(page2, queryWrapper);

    System.out.println("people List: " + result.getRecords() );
}

逻辑删除

对于内置Mapper,Mybatis Plus可以自动支持逻辑删除的功能。通过@TableLogic注解指定逻辑删除字段即可

/**
 * 逻辑删除标识,invalid:无效;valid:有效
 */
@TableLogic
private String flag;

而对于逻辑未删除的值、已删除的值即可直接通过注解配置,亦可进行全局配置

# Mybatis Plus 全局设置,逻辑已删除值
mybatis-plus.global-config.db-config.logic-delete-value=invalid
# Mybatis Plus 全局设置,逻辑未删除值
mybatis-plus.global-config.db-config.logic-not-delete-value=valid

为了实现逻辑删除,内置Mapper在自动注入SQL时也会发生一些变化。具体地:

  • 插入:无变化
  • 查找:一方面会追加where条件以过滤掉已删除的记录,另一方面,通过wrapper指定条件也会忽略逻辑删除字段的条件
  • 更新:一方面会追加where条件防止对已删除的记录进行更新,另一方面,通过wrapper指定条件也会忽略逻辑删除字段的条件
  • 删除:转变为更新语句,将 逻辑删除字段 设置为 逻辑已删除值

Note

对于主键,Mybatis Plus还支持在未指定主键的时候自动生成ID或UUID。具体地,其支持对某个表的单独设置、全局设置。前者可通过在主键属性上设置@TableId注解的type属性为IdType.ASSIGN_ID、IdType.ASSIGN_UUID实现;后者则可通过在配置文件中设置配置项 mybatis-plus.global-config.db-config.id-type 为 assign_id、assign_uuid 实现

posted @ 2021-12-08 18:53  And杰然  阅读(443)  评论(0编辑  收藏  举报