本章目录

  • AR模式
  • 主键策略
  • 基本配置

1. AR模式

Active Record(活动记录),是一种领域模型模式,特点是一个模型类对应关系型数据库中的一个表,而模型类的一个实例对应表中的一行记录,属于动态模型。而Java作为准静态语言,对于 ActiveRecord 往往只能感叹其优雅,所以 MP 也在 AR 道路上进行了一定的探索,才有了现在的功能Java也能实现AR模式。简而言之,就是直接用实体类对数据库进行CRUD操作,接下来看具体代码:

要实现AR模式需要两个前提:一是实体类继承Model抽象类,二是定义实体类对应的mapper接口继承BaseMapper。

entity实体类

@Data
@TableName("sys_member")
public class MemberAR extends Model<MemberAR> {

    @TableId
    private Long id;

    private String name;

    private String password;

    private Integer state;

    private Long superId;

    private LocalDateTime createTime;
}



:实体类继承Model类

mapper类



public interface MemberARMapper extends BaseMapper<MemberAR> {
}



:虽然AR模式用不到该接口,但是一定要定义,否则使用AR时会报空指针异常。

AR使用

(1).AR插入操作



@RequestMapping("/ar_insert")
    public Result insert() {
        MemberAR memberAR = new MemberAR();
        memberAR.setId(10L);
        memberAR.setName("第时");
        memberAR.setPassword("12345");
        memberAR.setState(2);
        memberAR.setSuperId(1L);
        memberAR.setCreateTime(LocalDateTime.now());

        boolean insert = memberAR.insert();
        
        System.out.println(insert);
        return ResultUtil.success(insert);
    }





为什么官方建议使用自增主键索引_1


:可以看到我们并不需要注入mapper接口,不过正如刚才所说,不使用但还是要定义,否则会报错。AR操作是通过对象本身调用相关方法,比如要insert一个memberAR,那就用这个memberAR调用insert方法即可。返回值为布尔类型,由上图可看到返回了true,是指操作成功。

(2).AR删除操作


@RequestMapping("/ar_delete")
    public Result deleteAR() {
        MemberAR memberAR = new MemberAR();
        //删除数据库中不存在的数据也是返回true
        //1.根据id删除
        //boolean deleteById = memberAR.deleteById(10L);
        //或者这样
        //memberAR.setId(10L);
        //boolean deleteById = memberAR.deleteById();

        //2.根据条件删除
        boolean delete = memberAR.delete(new QueryWrapper<MemberAR>().like("name", "第"));

        return ResultUtil.success(delete);
    }


:这里介绍了两个删除方法,代码中已有注释说明。需要注意的是,在MP中删除数据库中不存在的数据逻辑上也算删除,所以结果也是true。

(3).AR更新操作


@RequestMapping("/ar_update")
    public Result updateAR() {
        MemberAR memberAR = new MemberAR();
        memberAR.setId(10L);
        memberAR.setCreateTime(LocalDateTime.now());

        boolean updateById = memberAR.updateById();
        
        return ResultUtil.success(updateById);
    }


:memberAR调用updateById方法,将id为10的用户进行时间更新。


//  这里演示另一个方法insertOrUpdate
@RequestMapping("/ar_insertOrUpdate")
    public Result insertOrUpdateAR() {
        MemberAR memberAR = new MemberAR();
        //1.插入操作
        //memberAR.setName("张强");
        //memberAR.setPassword("12345");
        //boolean insertOrUpdate = memberAR.insertOrUpdate();

        //2.更新操作
        memberAR.setId(10L);
        memberAR.setCreateTime(LocalDateTime.now());
        boolean insertOrUpdate = memberAR.insertOrUpdate();

        return ResultUtil.success(insertOrUpdate);
    }


为什么官方建议使用自增主键索引_1_02


:当实体类对象中没有设置id时,memberAR调用insertOrUpdate方法为插入数据;当实体类对象中设置id时,如上图会先执行select操作,查询到该id对应的数据时则再使用update操作,查询不到该id对应的数据时则再使用insert操作。

(4).AR查询操作


@RequestMapping("/ar_select")
    public Result selectAR() {
        MemberAR memberAR = new MemberAR();
        //1.根据id查询
        //MemberAR ar = memberAR.selectById(10);
        // 或者这样
        //memberAR.setId(10L);
        //MemberAR ar = memberAR.selectById();

        //2.查询所有
        //List<MemberAR> ars = memberAR.selectAll();

        //3.根据条件查询
        //List<MemberAR> ars = memberAR.selectList(new QueryWrapper<MemberAR>().like("name", "第"));

        //4.查询符合条件的总数
        int count = memberAR.selectCount(new QueryWrapper<MemberAR>().eq("state", 1));
        
        return ResultUtil.success(count);
    }


:上面的代码涉及到了四个不同的查询操作,其实用法与MP的BaseMapper提供的方法的用法差不多,只不过这里是实体对象调用。

(5).AR分页操作


@RequestMapping("/ar_page")
    public Result pageAR() {
        MemberAR memberAR = new MemberAR();
        Page<MemberAR> selectPage = memberAR.selectPage(new Page<>(1, 4),
                new QueryWrapper<MemberAR>().eq("state", 1));

        List<MemberAR> selectPageRecords = selectPage.getRecords();

        return ResultUtil.success(selectPageRecords);
    }


为什么官方建议使用自增主键索引_1_03


:使用MP中的selectPage方法,传入page参数和where条件构造器,以每页4条数据查询出第1页的数据集合。该方法会先执行一条查询总记录数,再执行limit分页查询,如果不需要查询总记录数,可在page中设置第三个参数new Page<>(1, 4, false)。

2. 主键策略

MP中提供了多种主键策略,根据应用场景不同可对不同实体分别使用各自的主键策略,也可全局统一策略,接下来看具体代码:


@Data
@TableName("sys_member")
public class Member {

    /**
     * //1.设置主键自增,数据库同样要进行主键自增设置
     * @TableId(type = IdType.AUTO)
     *
     * //2.数据库不设置主键自增,实体类设置id则使用设置的id进行插入,实体类不设置id则使用默认的雪花算法
     * @TableId(type = IdType.NONE)
     *
     * //3.这个就是雪花算法(默认)
     * @TableId(type = IdType.ID_WORKER)
     *
     * //4.这个雪花算法要求id是String类型的
     * @TableId(type = IdType.ID_WORKER_STR)
     *
     * //5.UUID要求id为String类型
     * @TableId(type = IdType.UUID)
     *
     *  注:3、4、5 这三种主键策略只有当插入对象ID为空,才自动填充!
     */

    @TableId(type = IdType.AUTO)
    private Long id;

    //@TableField(condition = SqlCondition.LIKE)
    private String name;

    private String password;

    private Integer state;

    private Long superId;

    private LocalDateTime createTime;

}


在实体类中id属性上加上相应注解即可实现局部策略,另外全局策略需在application.yml中配置,需要注意的是局部策略大于全局策略,配置如下:


mybatis-plus:
  # MP设置全局id策略为uuid,局部设置id策略在实体类对象的id属性上设置(局部策略 大于 全局策略)
  global-config:
    db-config:
      id-type: uuid


:MP提供的每种主键策略我在代码中已经加上注释,对于不同的场景需要使用不同的策略,例如需要id无规则的时候就建议使用雪花算法和UUID。

3. 基本配置

(1).基本配置


mybatis-plus:
  # mybatis的自定义配置
  config-location: classpath:mybatis-config.xml


:在application.yml文件中配置如上数据,resources目录下创建mybatis-config.xml用来添加自己需要的mybatis配置。


mybatis-plus:
  # myBaits别名包扫描路径配置
  type-aliases-package: com.ethan.entity
<!-- 没有配置myBaits别名包扫描路径 -->
<mapper namespace="com.ethan.dao.MemberMapper">
    <select id="selectAllMembers" resultType="com.ethan.entity.Member">
        select * from sys_member ${ew.customSqlSegment}
    </select>

    <select id="selectMemberPage" resultType="com.ethan.entity.Member">
        select * from sys_member ${ew.customSqlSegment}
    </select>
</mapper>

<!-- 已配置myBaits别名包扫描路径 -->
<mapper namespace="com.ethan.dao.MemberMapper">
    <select id="selectAllMembers" resultType="Member">
        select * from sys_member ${ew.customSqlSegment}
    </select>

    <select id="selectMemberPage" resultType="Member">
        select * from sys_member ${ew.customSqlSegment}
    </select>
</mapper>


:myBaits别名包扫描路径,通过该属性可以给包中的类注册别名,注册后在Mapper对应的XML文件中可以直接使用类名,而不用使用全限定的类名。(即XML中调用的时候不用包含包名)

(2).进阶配置


mybatis-plus:
  configuration:
    # 是否开启自动驼峰命名规则映射,MP默认是开启的
    map-underscore-to-camel-case: true


:例如数据库列名 A_COLUMN(下划线命名) 到 Java 属性名 aColumn(驼峰命名) 的类似映射。如果您的数据库命名符合规则无需使用 @TableField 注解指定数据库字段名。

(3).DB策略配置


mybatis-plus:
  global-config:
    db-config:
      # 字段验证策略配置
      insert-strategy: not_null
      update-strategy: not_null
      select-strategy: not_null


:全局策略中这三个字段验证策略约定了如何产出注入的sql,涉及insert、update以及wrapper内部的entity属性生成的where条件,三个字段验证策略都有not_null、not_empty、ignored等属性,默认是not_null,及当字段没有设置值时不注入sql。


@TableField(insertStrategy = FieldStrategy.NOT_EMPTY)
private String name;


:也可以配置局部策略,局部策略优先于全局策略。当我们某个实体类中的某个属性不使用全局策略时,可单独配置局部策略,即在实体类属性上加上如上注解,FieldStrategy的属性跟全局策略中的属性一样。


mybatis-plus:
  global-config:
    db-config:
      # 表名前缀配置
      table-prefix: sys_


:表名前缀配置,当我们全库表名前缀一致时可使用该配置进行全局配置表名前缀,这样当我们编写实体类时就不需要像之前一样每个实体类上都加上@TableName("sys_xx")注解,只需实体类名与xx一致即可自动匹配对应数据库表。