0
点赞
收藏
分享

微信扫一扫

三:Mybatis-Plus通用CRUD

闲云困兽 2023-05-15 阅读 62


MyBatis-Plus为我们提供了BaseMapper,我们只需要继承BaseMapper就可以直接使用简单的增删改查功能。

一:Create(Insert)

int insert(T entity);

@Test
void testMyBatisPlus() {
    // INSERT INTO tbl_user ( username, name ) VALUES ( ?, ? )
    User user = new User();
    user.setUsername("gaozhanlong");
    user.setName("高占龙");

    // 返回受影响的行数
    // 插入时如果属性值为null则不加入到SQL中。
    // INSERT INTO tbl_user ( id, username, password, name ) VALUES ( ?, ?, ?, ? )
    int affectRows = userMapper.insert(user);
    // 插入后主键id会赋值给实体
    Long userId = user.getId();
    System.out.println("affectRows=" + affectRows + ", userId=" + userId);
}

public class User implements Serializable {
    /**
    * 主键
    */
    @TableId(type = IdType.AUTO)
    private Long id;
}

数据库的主键对应实体中属性需要使用@TableId注解标注,并指明主键id的生成策略,常用的有AUTO(数据库自增)、ASSIGN_ID(雪花算法),当插入成功后会将主键id值回显给实体对象,一般情况下id生成策略都使用ATUO,只有在有分表需求的时候才使用ASSIGN_ID(雪花算法)。

注意:最新版本的mybatis-plus中的雪花算法好像不需要配置数据中心ID和机器ID,它们都是自动计算出来的:

  • mybatis-plus.global-config.datacenter-id 根据服务器的Mac地址来计算
  • mybatis-plus.global-config.worker-id 根据datacenter-id和java虚拟中的bean数量来计算。

使用@TableId(type = IdType.AUTO)这种将注解标注在主键id属性上属于局部主键策略,我们也可以在application.yml中配置全局主键策略,当配置了全局id生成策略并且主键为“id”此时不用显式的使用@TableId注解,如果同时配置了全局策略和局部策略,那么局部策略优于全局策略。

# 配置mybatis plus 全局的id生成策略
mybatis-plus.global-config.db-config.id-type=auto

二:Delete

// 根据 entity 条件,删除记录
int delete(@Param(Constants.WRAPPER) Wrapper<T> wrapper);
// 删除(根据ID 批量删除)
int deleteBatchIds(@Param(Constants.COLLECTION) Collection<? extends Serializable> idList);
// 根据 ID 删除
int deleteById(Serializable id);
// 根据 columnMap 条件,删除记录
int deleteByMap(@Param(Constants.COLUMN_MAP) Map<String, Object> columnMap);

@Test
public void testDelete() {
    // DELETE FROM tbl_user WHERE id=?
    int affectRows = userMapper.deleteById(100L);

    // DELETE FROM tbl_user WHERE id IN ( ? , ? , ? )
    int num = userMapper.deleteBatchIds(Arrays.asList(1L, 2L, 3L));

    // 多条件删除,逻辑运算符使用and连接,关系运算符使用=连接,如果值为null表示 is null
    // DELETE FROM tbl_user WHERE username = ? AND status IS NULL
    Map<String, Object> whereMap = new HashMap<>();
    whereMap.put("username", "gaozhanlong");
    whereMap.put("status", null);
    int rows = userMapper.deleteByMap(whereMap);

    // 使用QueryWrapper构造where条件(这种方式最灵活,可以构造任意关系运算符和逻辑运算符)
    // DELETE FROM tbl_user WHERE (age > ? AND username LIKE ?)
    QueryWrapper<User> wrapper = new QueryWrapper<>();
    wrapper.gt("age", 30).likeRight("username", "xiao");
    int count = userMapper.delete(wrapper);
}

三:Update

// 根据 whereEntity 条件,更新记录
int update(@Param(Constants.ENTITY) T entity, @Param(Constants.WRAPPER) Wrapper<T> updateWrapper);
// 根据 ID 修改
int updateById(@Param(Constants.ENTITY) T entity);

@Test
void testMyBatisPlus() {
    // UPDATE tbl_user SET age=?, status=? WHERE id=?
    User user = new User();
    user.setId(1L);
    user.setAge(50);
    user.setStatus(2);

    int affectRows = userMapper.updateById(user);
    System.out.println(affectRows);
}

注意:修改时如果属性为null也是不会加入到SQL语句中来的。

@Test
public void testUpdate(){
    User user = new User();
    user.setAge(35);
    user.setRemark("重庆军统王牌特工,表面残酷狠辣的军统特务“鬼子六”");
    
    QueryWrapper<User> queryWrapper = new QueryWrapper();
    queryWrapper.eq("username", "sixbrother").gt("age", 20);

    // UPDATE tbl_user SET age=?, remark=? WHERE (username = ? AND age > ?)
    int affectRows = userMapper.update(user, queryWrapper);
    System.out.println(affectRows);
}


@Test
void testMyBatisPlus() {
   // UPDATE tbl_user SET age=?, status=? WHERE (id = ?)
   User user = new User();
   user.setId(1L);
   user.setAge(50);
   user.setStatus(2);

   QueryWrapper<User> queryWrapper = new QueryWrapper<User>().eq("id", 100L);
   int affectRows = userMapper.update(user, queryWrapper);
   System.out.println(affectRows);
}

UpdateWrapper可以通过set方法来设置字段的值。

@Test
void testMyBatisPlus() {
    // UPDATE tbl_user SET age=?,status=? WHERE (id = ?)
    UpdateWrapper<User> updateWrapper = new UpdateWrapper<User>()
            .set("age", 30)
            .set("status", 2)
            .eq("id", 100L);

    int affectRows = userMapper.update(null, updateWrapper);
    System.out.println(affectRows);
}

UpdateWrapper可以通过setSql() 采用SQL语法来设置值。

@Test
void testMyBatisPlus() {
    // UPDATE tbl_user SET age=?,status = 2 WHERE (id = ?)
    LambdaUpdateWrapper<User> updateWrapper = new LambdaUpdateWrapper<User>()
            .set(User::getAge, 30)
            .setSql("status = 2")
            .eq(User::getId, 100L);

    int affectRows = userMapper.update(null, updateWrapper);
    System.out.println(affectRows);
}

注意:

  • QueryWrapper:用于构造where条件的,SQL中的条件在QueryWrapper中都有对应的方法。
  • QueryWrapper默认是使用and 并且来连接各个条件的。
  • UpdateWrapper:用于构造update语句,比QueryWrapper多了一个set()方法用于修改值,也可以使用QueryWrapper中的方法来构造where条件。

四:Retrieve(Select)

// 根据 ID 查询
T selectById(Serializable id);
// 根据 entity 条件,查询一条记录
T selectOne(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);

// 查询(根据ID 批量查询)
List<T> selectBatchIds(@Param(Constants.COLLECTION) Collection<? extends Serializable> idList);
// 根据 entity 条件,查询全部记录
List<T> selectList(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);
// 查询(根据 columnMap 条件)
List<T> selectByMap(@Param(Constants.COLUMN_MAP) Map<String, Object> columnMap);
// 根据 Wrapper 条件,查询全部记录
List<Map<String, Object>> selectMaps(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);
// 根据 Wrapper 条件,查询全部记录。注意: 只返回第一个字段的值
List<Object> selectObjs(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);

// 根据 entity 条件,查询全部记录(并翻页)
IPage<T> selectPage(IPage<T> page, @Param(Constants.WRAPPER) Wrapper<T> queryWrapper);
// 根据 Wrapper 条件,查询全部记录(并翻页)
IPage<Map<String, Object>> selectMapsPage(IPage<T> page, @Param(Constants.WRAPPER) Wrapper<T> queryWrapper);
// 根据 Wrapper 条件,查询总记录数
Integer selectCount(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);

@Test
public void testSelect() {
    // SELECT * FROM tbl_user WHERE id=?
    User user = userMapper.selectById(1L);
    System.out.println(user);

    // SELECT * FROM tbl_user WHERE id IN ( ? , ? )
    List<User> users = userMapper.selectBatchIds(Arrays.asList(1L, 2L));
    System.out.println(users);

    // 查询一条,如果有多条满足条件的数据会报错
    // SELECT * FROM tbl_user WHERE (username = ?)
    QueryWrapper<User> queryWrapper = new QueryWrapper<>();
    queryWrapper.eq("username", "sixbrother");
    User user1 = userMapper.selectOne(queryWrapper);

    // 查询满足条件的条数
    // SELECT COUNT( 1 ) FROM tbl_user WHERE (username LIKE ?)
    QueryWrapper<User> wrapper = new QueryWrapper<>();
    wrapper.like("username", "xiao");
    Integer count = userMapper.selectCount(wrapper);

    // SELECT * FROM tbl_user WHERE (username LIKE ?)
    List<User> userList = userMapper.selectList(wrapper);
}

selectMaps()通常用于统计查询,因为一般统计的结果字段都不在实体类中。

@Test
void testMyBatisPlus() {
    // SELECT gender,count(*) as count,avg(age) as avg_age FROM tbl_user GROUP BY gender
    QueryWrapper<User> queryWrapper = Wrappers.<User>query()
            .select("gender", "count(*) as count", "avg(age) as avg_age").groupBy("gender");

    List<Map<String, Object>> maps = userMapper.selectMaps(queryWrapper);
    System.out.println(maps);
}

五:自定义SQL

自定义SQL就是又想自己写SQL语句又想使用MyBatis-Plus中的条件构造器Wrapper,MyBatis-Plus中可以支持此方式,通过使用@Param注解即可引用条件构造器。

BaseMapper中的很多方法参数都使用了@Param注解进行标注了,这就意味着我们可以在原生的MyBatis中使用这个参数(可以在MyBatis注解中也可以在xml文件中),例如使用@Param(Constants.WRAPPER) 定义参数名,在MyBatis中使用固定的写法${ew.customSqlSegment}来引用MyBatis-Plus中的条件构造器。

@Test
void testMyBatisPlus() {
    // delete from tbl_user WHERE (id = ? OR age > ?)
    QueryWrapper<User> wrapper = new QueryWrapper<User>().eq("id", 100).or().gt("age", 30);
    userMapper.myDelete(wrapper);
}

public interface UserMapper extends BaseMapper<User> {
	// 注意SQL语句不需要加where关键字
	@Delete("delete from tbl_user ${ew.customSqlSegment}")
    void myDelete(@Param(Constants.WRAPPER) QueryWrapper<User> wrapper);
}

六:@TableField

@TableField用于指定字段的一些属性,常用的场景有:

  • 对象中的属性名和字段名不一致的问题,如表中使用user_id作为主键,而实体中使用id作为属性名,此时需要配置两者的映射关系。

@TableName("tbl_user")
public class User implements Serializable {
    /**
     * 主键
     */
    @TableId(type = IdType.AUTO)
    @TableField(value = "user_id")
    private Long id;
}

  • 对象中的属性字段在表中不存在的问题。

@TableName("tbl_user")
public class User implements Serializable {
	/** 数据库中不存在的字段 */
    @TableField(exist = false)
    private String mock;
}

  • 查询时不查询指定的字段,如有些字段只是服务器在使用,没必要暴露出去

@TableName("tbl_user")
public class User implements Serializable {
	/**
     * 版本号
     */
    @TableField(select = false)
    private String version;

	/**
    * 是否删除(0: 未删除,1:已删除)
    */
    @TableField(select = false)
    private Integer deleted;
}


举报

相关推荐

0 条评论