MybatisPlus 通用CRUD操作

作者: adm 分类: java,mybatis 发布时间: 2022-12-13

1、插入操作
1.1、方法定义

/**
* 插⼊⼀条记录
*
* @param entity 实体对象.
*/
int insert(T entity);

1.2、测试用例

   /*
        测试添加
     */
    @Test
    public void testInsert(){
 
        User user = new User();
        user.setName("应颠22");
        user.setAge(20);
        user.setMail("zimu@lagou.com");
 
        // 返回值是影响的行数
        int result = userMapper.insert(user);
        System.out.println(result);
 
        System.out.println("id值为" + user.getId());
        // 这里我们没有设置id,但是user中却能获取值,是因为MybatisPlus自动帮我们生成的
 
    }

2、更新操作
在MP中,更新操作有2种,⼀种是根据id更新,另⼀种是根据条件更新。

2.1、根据id更新
方法定义

/**
* 根据 ID 修改
*
* @param entity 实体对象
*/
int updateById(@Param(Constants.ENTITY) T entity);

测试:

  /*
        测试根据ID进行修改
     */
    @Test
    public void testUpateById(){
        User user = new User();
        user.setId(6L);
        user.setAge(30);//更新的字段
        //根据id更新,更新不为null的字段
        int i = userMapper.updateById(user);
        System.out.println(i);
    }

2.2、根据条件更新
方法定义

/**
* 根据 whereEntity 条件,更新记录
*
* @param entity 实体对象 (set 条件值,可以为 null)
* @param updateWrapper 实体对象封装操作类(可以为 null,⾥⾯的 entity ⽤于⽣成where 语句)
*/
int update(@Param(Constants.ENTITY) T entity, @Param(Constants.WRAPPER) Wrapper updateWrapper);

测试用例

 /*
     测试根据条件进行修改
  */
    @Test
    public void testUpate(){
 
        // 1. 更新的字段
        User user = new User();
        user.setAge(35);
 
        // 2.更新的条件
        QueryWrapper queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("name","子慕");
 
        int i = userMapper.update(user,queryWrapper);
        System.out.println(i);
    }
 
// 通过UpdateWrapper进⾏更新
    @Test
    public void testUpate2(){
 
        UpdateWrapper updateWrapper = new UpdateWrapper<>();
        updateWrapper.eq("id",6).set("age",40);
 
 
        int i = userMapper.update(null,updateWrapper);
        System.out.println(i);
    }

3、删除操作
3.1、deleteById
方法定义

/**
* 根据 ID 删除
*
* @param id 主键ID
*/
int deleteById(Serializable id);

测试用例

   /*
        根据ID进行删除
     */
    @Test
    public void testDeleteById(){
        int i = userMapper.deleteById(2L);
        System.out.println(i);
    }

3.2、deleteByMap
方法定义:

/**
* 根据 columnMap 条件,删除记录
*
* @param columnMap 表字段 map 对象
*/
int deleteByMap(@Param(Constants.COLUMN_MAP) Map columnMap);

测试用例

  /*
      根据columnMap进行删除
   */
    @Test
    public void testDeleteByMap(){
 
        HashMap map = new HashMap<>();
        map.put("name","子慕");
        map.put("age",18);
 
        // 将columnMap中的元素设置为删除的条件,多个条件是and的关系
        int i = userMapper.deleteByMap(map);
        System.out.println(i);
    }

3.3、delete
方法定义

/**
* 根据 entity 条件,删除记录
*
* @param wrapper 实体对象封装操作类(可以为 null)
*/
int delete(@Param(Constants.WRAPPER) Wrapper wrapper);

测试用例

    /*
       调用delete进行删除
    */
    @Test
    public void testDelete(){
        
        User user = new User();
        user.setName("子慕2");
        user.setAge(18);
 
        QueryWrapper queryWrapper = new QueryWrapper<>(user);
       // queryWrapper.eq("name","子慕1").eq("age",18);
 
        int i = quserMapper.delete(queryWrapper);
        System.out.println(i);
    }

3.4、deleteBatchIds
方法定义

/**
* 删除(根据ID 批量删除)
*
* @param idList 主键ID列表(不能为 null 以及 empty)
*/
int deleteBatchIds(@Param(Constants.COLLECTION) Collection idList);

测试用例

/*
         调用deleteBatchIds进行批量删除
    */
    @Test
    public void testDeleteBatchIds(){
 
        int i = userMapper.deleteBatchIds(Arrays.asList(10l,11l));
        System.out.println(i);
    }

4、查询操作
MP提供了多种查询操作,包括根据id查询、批量查询、查询单条数据、查询列表、分⻚查询等操作。

4.1、selectById
方法定义:

/**
* 根据 ID 查询
*
* @param id 主键ID
*/
T selectById(Serializable id);

测试用例

    /*
        根据ID进行查询
     */
    @Test
    public void testSelectById(){
        User user = userMapper.selectById(2L);
        System.out.println(user);
    }

4.2、selectBatchIds
方法定义

/**
* 查询(根据ID 批量查询)
*
* @param idList 主键ID列表(不能为 null 以及 empty)
*/
List selectBatchIds(@Param(Constants.COLLECTION) Collection idList);

测试用例

    /*
      根据ID进行批量查询
   */
    @Test
    public void testSelectBatchIds(){
 
        List users = userMapper.selectBatchIds(Arrays.asList(12L, 13l));
        for (User user : users) {
            System.out.println(user);
        }
    }

4.3、selectOne
方法定义

/**
* 根据 entity 条件,查询⼀条记录
*
* @param queryWrapper 实体对象封装操作类(可以为 null)
*/
T selectOne(@Param(Constants.WRAPPER) Wrapper queryWrapper);

测试用例

    /*
       测试selectOne
    */
    @Test
    public void testSelectOne(){
 
        QueryWrapper queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("name","子慕");
 
        // 根据条件查询一条记录,如果查询结果超过一条,会报错
        User user = userMapper.selectOne(queryWrapper);
        System.out.println(user);
    }

4.4、selectCount
方法定义

/**
* 根据 Wrapper 条件,查询总记录数
*
* @param queryWrapper 实体对象封装操作类(可以为 null)
*/
Integer selectCount(@Param(Constants.WRAPPER) Wrapper queryWrapper);

测试用例

  /*
        根据wrapper条件,查询总记录数
     */
    @Test
    public void testSelectCount(){
 
        QueryWrapper queryWrapper = new QueryWrapper<>();
        queryWrapper.gt("age",18); // 查询年龄大于18的
 
        // 根据条件查询一条记录,如果查询结果超过一条,会报错
        Integer count = userMapper.selectCount(queryWrapper);
        List users = userMapper.selectList(queryWrapper);
        System.out.println(count);
        for (User user : users) {
            System.out.println(user);
        }
 
    }

4.5、selectList
方法定义

/**
* 根据 entity 条件,查询全部记录
*
* @param queryWrapper 实体对象封装操作类(可以为 null)
*/
List selectList(@Param(Constants.WRAPPER) Wrapper queryWrapper);

测试用例

 @Test
    public void testSelectList() {
        QueryWrapper wrapper = new QueryWrapper();
        wrapper.gt("age", 23); //年龄⼤于23岁
//根据条件查询数据
        List users = this.userMapper.selectList(wrapper);
        for (User user : users) {
            System.out.println("user = " + user);
        }
    }

4.6、selectPage
方法定义

/**
* 根据 entity 条件,查询全部记录(并翻⻚)
*
* @param page 分⻚查询条件(可以为 RowBounds.DEFAULT)
* @param queryWrapper 实体对象封装操作类(可以为 null)
*/
IPage selectPage(IPage page, @Param(Constants.WRAPPER) Wrapper queryWrapper);

配置分页插件:

   @Configuration
    @MapperScan("com.lagou.mp.mapper") //设置mapper接⼝的扫描包
    public class MybatisPlusConfig {
        /**
         * 分⻚插件
         */
        @Bean
        public PaginationInterceptor paginationInterceptor() {
            return new PaginationInterceptor();
        }
    }

测试用例

    /*
     分页查询
  */
    @Test
    public void testSelectPage(){
 
        QueryWrapper queryWrapper = new QueryWrapper<>();
        queryWrapper.gt("age",18); // 查询年龄大于18的
 
        // 第一个参数:当前页   第二个参数:每页显示条数
        Page page = new Page<>(2, 2);
        
        IPage userIPage = userMapper.selectPage(page, queryWrapper);
        System.out.println("总条数" + userIPage.getTotal());
        System.out.println("总页数" + userIPage.getPages());
 
        System.out.println("分页数据" + userIPage.getRecords());
    }

5、SQL注入的原理
前⾯我们已经知道,MP在启动后会将BaseMapper中的⼀系列的⽅法注册到meppedStatements中,那么究竟是如何注⼊的呢?流程⼜是怎么样的?下⾯我们将⼀起来分析下。
在MP中,ISqlInjector负责SQL的注⼊⼯作,它是⼀个接⼝,AbstractSqlInjector是它的实现类,实现关系如下:

在AbstractSqlInjector中,主要是由inspectInject()⽅法进⾏注⼊的,如下:

    @Override
    public void inspectInject(MapperBuilderAssistant builderAssistant, Class
            mapperClass) {
        Class modelClass = extractModelClass(mapperClass);
        if (modelClass != null) {
            String className = mapperClass.toString();
            Set mapperRegistryCache =
                    GlobalConfigUtils.getMapperRegistryCache(builderAssistant.getConfiguration());
            if (!mapperRegistryCache.contains(className)) {
                List methodList = this.getMethodList();
                if (CollectionUtils.isNotEmpty(methodList)) {
                    TableInfo tableInfo =
                            TableInfoHelper.initTableInfo(builderAssistant, modelClass);
                    // 循环注⼊⾃定义⽅法
                    methodList.forEach(m -> m.inject(builderAssistant,
                            mapperClass, modelClass, tableInfo));
                } else {
                    logger.debug(mapperClass.toString() + ", No effective
                            injection method was found.");
                }
                mapperRegistryCache.add(className);
            }
        }
    }

在实现⽅法中, methodList.forEach(m -> m.inject(builderAssistant, mapperClass,modelClass, tableInfo)); 是关键,循环遍历⽅法,进⾏注⼊。

最终调⽤抽象⽅法injectMappedStatement进⾏真正的注⼊:

/**
* 注⼊⾃定义 MappedStatement
*
* @param mapperClass mapper 接⼝
* @param modelClass mapper 泛型
* @param tableInfo 数据库表反射信息
* @return MappedStatement
*/
public abstract MappedStatement injectMappedStatement(Class mapperClass, Class modelClass, TableInfo tableInfo);

查看该⽅法的实现:

以SelectById为例查看:

    public class SelectById extends AbstractMethod {
        @Override
        public MappedStatement injectMappedStatement(Class mapperClass, Class modelClass, TableInfo tableInfo) {
            SqlMethod sqlMethod = SqlMethod.LOGIC_SELECT_BY_ID;
            SqlSource sqlSource = new RawSqlSource(configuration,
                    String.format(sqlMethod.getSql(),
                            sqlSelectColumns(tableInfo, false),
                            tableInfo.getTableName(), tableInfo.getKeyColumn(),
                            tableInfo.getKeyProperty(),
                            tableInfo.getLogicDeleteSql(true, false)), Object.class);
            return this.addSelectMappedStatement(mapperClass, sqlMethod.getMethod(), sqlSource, modelClass, tableInfo);
        }
    }

可以看到,⽣成了SqlSource对象,再将SQL通过addSelectMappedStatement⽅法添加到meppedStatements中。

如果觉得我的文章对您有用,请随意赞赏。您的支持将鼓励我继续创作!