学会MyBatis-Plus,我再也不用写SQL了?

MyBatis-Plus

以下内容若有误,欢迎私信我或在下方留言,谢谢^_−


官网:MyBatis-Plus (baomidou.com)

一、简介

MyBatis-Plus简称MP,对原来的 MyBatis 进行了增强,目的是为了简化开发、提高效率。其具有多种特性,比如

低侵入:引入MyBatis-Plus后并不会对现有的项目产生影响,这也是MyBatis-Plus的愿景,只做增强,不做改变。

损耗小:当我们引入依赖的时候,我们会发现该依赖的id带有starter,说明这是一个支持自动装配的工具,所以,在项目启动时就会自动注入基本的CRUD,对于性能来说基本没有任何损耗。

分页插件支持多种数据库:比如MySQL、Oracle、DB2、SQLServer等

支持主键自动生成:MyBatis-Plus支持多种主键策略,包含生成分布式系统中唯一ID

支持Lambda 形式调用、内置分页插件、强大的CRUD操作等。

在这里插入图片描述

MyBatisMP
优点 ①SQL语句自由控制,较为灵活
②SQL与业务层分离,易于阅读
③提供动态SQL语句,控制灵活
①提供无代码的CRUD操作
②内置代码生成器,比如分页插件、性能分析插件等
③提供了功能丰富的条件构造器
缺点 ①简单的CRUD也需要提供对应SQL语句
②需要维护大量的xml文件
③自身功能有限,要拓展需要依赖第三方插件
①增强了学习成本
②mybatis-plus引入第三方插件,未来升级可能会存在兼容性问题
<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-boot-starter</artifactId>
    <version>3.4.0</version>
</dependency>
二、常用注解
注解说明
@TableName()表名注解,指定当前实体类对应数据库中的哪张表,默认与实体类名一致
@TableField()字段注解(非主键),指定当前属性与表中哪一列映射,默认与属性名一致
@TableId()主键注解,标记当前属性映射表中主键(实体类中id没有明确指定id生成规则时,默认使用雪花算法)
@Version()用于标记乐观锁操作字段

在这里插入图片描述

@TableName("t_employee")
public class Employee_bak {
    @TableId(value = "id", type = IdType.AUTO)  // type 主键类型
    private Long id;
    @TableField(value = "ename")    // value 表中列名
    private String name;
    private String password;
    private String email;
    private int age;
    private int admin;
    private Long deptId;
    @TableField(exist = false)  // exist 是否为数据库表字段
    private Department dept;
}

参数丢失:由于一些不当的操作,将数据库中的某些数据丢失了

mybatis-plus sql拼接规则:

①实体对象属性有值,则属性名会拼接到SQL中

②实体对象属性类型为基本类型,会有默认值,mybatis-plus认为有值,参与SQL拼接

解决方案:

①将基本数据类型改为包装类型

②执行查询,再替换,后更新

③部分字段更新update(null, wrapper) / 自定义update sql

三、通用Mapper接口

日志

第一种:logging.level.cn.regex.mp.mapper=debug

第二种:mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl

1.insert
// int insert(T entity);
// INSERT INTO employee ( name, password, email, age, admin, dept_id ) VALUES ( ?, ?, ?, ?, ?, ? )
@Test
public void testInsert(){
  Employee employee = new Employee();
  employee.setAdmin(1);
  employee.setAge(18);
  employee.setDeptId(1L);
  employee.setEmail("regex@qq.com");
  employee.setName("regex");
  employee.setPassword("123");
  employeeMapper.insert(employee);
}
2.delete
  • deleteById:单个删除,根据指定 ID 删除一条记录

    // int deleteById(Serializable id);
    // DELETE FROM employee WHERE id=?
    @Test
    public void testDeleteById() {
        employeeMapper.deleteById(1L);
    }
    
  • deleteBatchIds:批量删除,根据给定的 ID 集合删除多条记录

    // int deleteBatchIds(@Param(Constants.COLLECTION) Collection<? extends Serializable> idList);
    // DELETE FROM employee WHERE id IN ( ? , ? )
    @Test
    public void testDeleteBatchIds() {
        employeeMapper.deleteBatchIds(Arrays.asList(1L, 2L));
    }
    
  • delete:条件删除,根据 entity 条件删除记录

    // int delete(@Param(Constants.WRAPPER) Wrapper<T> wrapper);
    // DELETE FROM employee WHERE (name = ? AND age = ?)
    @Test
    public void testDelete() {
        QueryWrapper<Employee> wrapper = new QueryWrapper<>();
        wrapper.eq("name", "一明");
        wrapper.eq("age", 25);
        employeeMapper.delete(wrapper);
    }
    
  • deleteByMap:条件删除,根据 columnMap 条件删除记录

    // int deleteByMap(@Param(Constants.COLUMN_MAP) Map<String, Object> columnMap);
    // DELETE FROM employee WHERE name = ? AND age = ?
    @Test
    public void testDeleteByMap() {
        Map<String, Object> map = new HashMap<>();
        map.put("name", "赵一明");
        map.put("age", 25);
        employeeMapper.deleteByMap(map);
    }
    
3.update
  • updateById:根据 ID 修改

    // int updateById(@Param(Constants.ENTITY) T entity);
    // UPDATE employee SET name=?, age=?, admin=? WHERE id=?
    @Test
    public void testUpdateById() {
        Employee employee = new Employee();
        employee.setId(1L);
        employee.setName("dafei");
        employeeMapper.updateById(employee);    // 拼接不为null的属性到SQL中
    }
    

    该方法会将不为null的属性拼接到SQL中,若实体类中包含基本数据类型,则可能导致数据丢失

  • update:根据 whereEntity 条件更新记录

    // int update(@Param(Constants.ENTITY) T entity, @Param(Constants.WRAPPER) Wrapper<T> updateWrapper);
    // UPDATE employee SET name=? WHERE (id = ?)
    @Test
    public void testUpdate() {
        UpdateWrapper<Employee> wrapper = new UpdateWrapper<>();
        wrapper.eq("id", 1L);
        wrapper.set("name", "regex");
        employeeMapper.update(null, wrapper);
    }
    
updateById和update选用问题:

如果更新条件是id,并且是全量更新,则使用updateById

如果更新条件不仅限于id,并且部分列更新,则使用update

4.select
  • selectList:根据 entity 条件,查询全部记录

    // List<T> selectList(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);
    // SELECT id,name,password,email,age,admin,dept_id FROM employee
    @Test
    public void testSelectList() {
        Wrapper<Employee> wrapper = new QueryWrapper<>();
        employeeMapper.selectList(wrapper);
    }
    
  • selectById:根据 ID 查询

    // T selectById(Serializable id);
    // SELECT id,name,password,email,age,admin,dept_id FROM employee WHERE id=?
    @Test
    public void testSelectById() {
        employeeMapper.selectById(5L);
    }
    
  • selectBatchIds:根据 ID 批量查询

    // List<T> selectBatchIds(@Param(Constants.COLLECTION) Collection<? extends Serializable> idList);
    // SELECT id,name,password,email,age,admin,dept_id FROM employee WHERE id IN ( ? , ? , ? )
    @Test
    public void testSelectBatchIds() {
       employeeMapper.selectBatchIds(Arrays.asList(2L, 3L, 4L));
    }
    
  • selectCount:根据 Wrapper 条件,查询总记录数

    // Integer selectCount(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);
    // SELECT COUNT( 1 ) FROM employee
    @Test
    public void testSelectCount() {
       employeeMapper.selectCount(null);
    }
    
  • selectByMap:根据 columnMap 条件查询

    // List<T> selectByMap(@Param(Constants.COLUMN_MAP) Map<String, Object> columnMap);
    // SELECT id,name,password,email,age,admin,dept_id FROM employee WHERE name = ? AND admin = ? AND age = ?
    @Test
    public void testSelectByMap() {
       Map<String, Object> map = new HashMap<>();
       map.put("name", "孙总");
       map.put("age", 35);
       map.put("admin", 0);
       employeeMapper.selectByMap(map);
    }
    
  • selectMaps:根据 Wrapper 条件查询全部记录,每条记录以键值对形式封装到map中

    // List<Map<String, Object>> selectMaps(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);
    // SELECT id,name,password,email,age,admin,dept_id FROM employee
    @Test
    public void testSelectMaps() {
        Wrapper<Employee> wrapper = new QueryWrapper<>();
        List<Map<String, Object>> maps = employeeMapper.selectMaps(wrapper);
        maps.forEach(System.err::println);
    }
    
  • selectPage:分页查询

    注意:需要在启动类中配置分页拦截器

    // 分页拦截器
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        PaginationInnerInterceptor paginationInnerInterceptor = new PaginationInnerInterceptor(DbType.MYSQL);
        paginationInnerInterceptor.setOverflow(true); //合理化
        interceptor.addInnerInterceptor(paginationInnerInterceptor);
        return interceptor;
    }
    
    // <E extends IPage<T>> E selectPage(E page, @Param(Constants.WRAPPER) Wrapper<T> queryWrapper);
    // SELECT id,name,password,email,age,admin,dept_id FROM employee LIMIT ?
    @Test
    public void testSelectPage() {
        Page<Employee> page = new Page<>(1, 5); // 默认第一页,每页10条
        Wrapper<Employee> wrapper = new QueryWrapper<>();
        Page<Employee> employeePage = employeeMapper.selectPage(page, wrapper);
        System.out.println("当前页:" + employeePage.getCurrent());
        System.out.println("页条数:" + employeePage.getSize());
        System.out.println("总条数:" + employeePage.getTotal());
        System.out.println("总页数:" + employeePage.getPages());
        System.out.println("数据集:" + employeePage.getRecords());
    }
    
selectList和selectMaps选用问题:

当所查询的的数据无法封装成对象时,使用selectMaps

四、条件构造器

条件构造器即根据条件拼接sql的where条件,可以理解为mybatis中的动态SQL或SQL片段

1.继承体系

在这里插入图片描述

  • Wrapper:条件构造抽象类,最顶端父类

    • AbstractWrapper: 用于查询条件封装,生成 sql 的 where 条件

      • AbstractLambdaWrapper: Lambda 语法使用 Wrapper 统一处理解析 lambda 获取 column

        • LambdaQueryWrapper:用于 Lambda 语法封装查询条件

        • LambdaUpdateWrapper: 用于 Lambda 语法封装更新条件

    • QueryWrapper: 封装查询条件

    • UpdateWrapper: 条件封装,用于Entity对象更新操作

2.更新操作

eq():用于拼接where条件

set():用于拼接set后面所需要修改的字段和值

// 需求:将id=1的员工age改为18, 如果传入uname变量值不等于null或者“”,修改为员工name为uname变量值
// UPDATE employee SET age=?,name=? WHERE (id = ?)
@Test
public void testUpdate2() {
    UpdateWrapper<Employee> wrapper = new UpdateWrapper<>();
    wrapper.eq("id", 1);
    wrapper.set("age", 18);
    String uname = "regex+";
    if (StringUtils.hasText(uname)) {
        wrapper.set("name", uname);
    }
    employeeMapper.update(null, wrapper);
}

setSql():用于拼接set后面所需要SQL片段

// 需求:将id=1的用户name改为regex
// UPDATE employee SET age=20,name='regex' WHERE (id = ?)
@Test
public void testUpdate3() {
    UpdateWrapper<Employee> wrapper = new UpdateWrapper<>();
    wrapper.eq("id", 1L);
    wrapper.setSql("age=20");
    String name = "regex";
    wrapper.setSql(StringUtils.hasText(name), "name='regex'");  // 里面的regex需要加上单引号
    employeeMapper.update(null, wrapper);
}

Lambda 方式更新封装(推荐

// 需求:将id=1的用户name改为regex
// UPDATE employee SET name=? WHERE (id = ?)
@Test
public void testUpdate4() {
    LambdaUpdateWrapper<Employee> wrapper = new LambdaUpdateWrapper<>();
    wrapper.eq(Employee::getId, 1L);
    wrapper.set(Employee::getName, "regex");
    employeeMapper.update(null, wrapper);
}
3.查询操作

Lambda 语法使用 Wrapper + 链式编程

// 需求:查询name=regex, age=18的用户
// SELECT id,name,password,email,age,admin,dept_id FROM employee WHERE (name = ? AND age = ?)
@Test
public void testSelect2() {
    LambdaQueryWrapper<Employee> wrapper = new LambdaQueryWrapper<>();
    wrapper.eq(Employee::getName, "regex").eq(Employee::getAge, 40);
    employeeMapper.selectList(wrapper);
}
4.工具类Wappers
  • new方式

    QueryWrapper<Employee> wrapper1 = new QueryWrapper<>();
    LambdaQueryWrapper<Employee> wrapper2 = new LambdaQueryWrapper<>();
    
  • 工具类创建

    QueryWrapper<Employee> wrapper3 = Wrappers.<Employee>query();
    LambdaQueryWrapper<Employee> wrapper4 = Wrappers.<Employee>lambdaQuery();
    
  • QueryWrapper --> LambdaQueryWrapper

    LambdaQueryWrapper<Employee> wrapper5 = wrapper1.lambda();
    
五、高级查询
1.列投影

在这里插入图片描述

select(String… columns):选择需要查询的列

// 需求:查询所有员工, 返回员工name, age列
// SELECT name, age FROM employee
@Test
public void testQuery1() {
    QueryWrapper<Employee> wrapper = new QueryWrapper<>();
    wrapper.select("name", "age");
    // wrapper.select("name, age");    // SQL片段
    employeeMapper.selectList(wrapper);
}

// 需求:查询所有员工, 返回以a字母开头的列
// SELECT id,age,admin FROM employee
@Test
public void testQuery2() {
    QueryWrapper<Employee> wrapper = new QueryWrapper<>();
    wrapper.select(Employee.class, TableFieldInfo -> TableFieldInfo.getProperty().startsWith("a"));	// 过滤查询字段不含主键
    employeeMapper.selectList(wrapper);
}
2.排序

在这里插入图片描述

// 需求:查询所有员工信息按age正序排, 如果age一样, 按id降序排
@Test
public void testOrder() {
    QueryWrapper<Employee> wrapper = new QueryWrapper<>();
    // wrapper.orderByAsc("age").orderByDesc("id");
    wrapper.orderBy(true, true, "name");
    employeeMapper.selectList(wrapper);
}
3.分组查询

在这里插入图片描述

// 需求: 以部门id进行分组查询,查每个部门员工个数, 将大于3人的部门过滤出来
// SELECT count(*) FROM employee GROUP BY dept_id
@Test
public void testGroup() {
    QueryWrapper<Employee> wrapper = new QueryWrapper<>();
    wrapper.groupBy("dept_id")
            .select("dept_id", "count(*) '人数'")
            // 只能够使用{0}进行占位
            .having("count(*) > {0}", 3);
            //.having("count(*) > 3");
    employeeMapper.selectList(wrapper);
}
4.条件查询
比较运算符含义
allEq/eq/ne全等于/等于/不等于
gt/ge/lt/le大于/大于等于/小于/小于等于
between/notBetween在…之间/不在…之间
isNull/isNotNull为空/不为空
in/notIn包含/不包含(字段方式)
inSql/notInSql包含/不包含(SQL片段方式)
// 查询name=regex, age=18的员工信息
// SELECT id,name,password,email,age,admin,dept_id FROM employee WHERE (name = ? AND age = ?)
@Test
public void testAllEq() {
    QueryWrapper<Employee> wrapper = new QueryWrapper<>();
    Map<String, Object> map = new HashMap<>();
    map.put("name", "regex");
    map.put("age", "40");
    wrapper.allEq(map);
    employeeMapper.selectList(wrapper);
}

// 需求:查询满足条件员工信息, 注意传入的map条件中, 包含a的列才参与条件查询
// SELECT id,name,password,email,age,admin,dept_id FROM employee WHERE (name = ?)
@Test
public void testAllEq2() {
    QueryWrapper<Employee> wrapper = new QueryWrapper<>();
    Map<String, Object> map = new HashMap<>();
    map.put("name", "regex");
    map.put("age", "40");
    wrapper.allEq((k, v) -> k.contains("m"), map);
    employeeMapper.selectList(wrapper);
}

// 需求:查询name=regex员工信息
// SELECT id,name,password,email,age,admin,dept_id FROM employee WHERE (name = ?)
@Test
public void testEq() {
    QueryWrapper<Employee> wrapper = new QueryWrapper<>();
    wrapper.eq("name", "regex");
    employeeMapper.selectList(wrapper);
}

// 需求:查询name !=dafei员工信息
// SELECT id,name,password,email,age,admin,dept_id FROM employee WHERE (name <> ?)
@Test
public void testNe() {
    QueryWrapper<Employee> wrapper = new QueryWrapper<>();
    wrapper.ne("name", "regex");
    employeeMapper.selectList(wrapper);
}

// 需求:查询age 大于18岁员工信息
// SELECT id,name,password,email,age,admin,dept_id FROM employee WHERE (age > ?)
@Test
public void testGt() {
    QueryWrapper<Employee> wrapper = new QueryWrapper<>();
    wrapper.gt("age", 18);
    employeeMapper.selectList(wrapper);
}

// 需求:查询年龄介于18~30岁的员工信息
// SELECT id,name,password,email,age,admin,dept_id FROM employee WHERE (age BETWEEN ? AND ?)
@Test
public void testBetween() {
    QueryWrapper<Employee> wrapper = new QueryWrapper<>();
    wrapper.between("age", 18, 30);
    employeeMapper.selectList(wrapper);
}

// 需求:查询年龄小于18或者大于30岁的员工信息【用between实现】
// SELECT id,name,password,email,age,admin,dept_id FROM employee WHERE (age NOT BETWEEN ? AND ?)
@Test
public void testNotBetween() {
    QueryWrapper<Employee> wrapper = new QueryWrapper<>();
    wrapper.notBetween("age", 18, 30);
    employeeMapper.selectList(wrapper);
}

@Test
public void testNull() {
    QueryWrapper<Employee> wrapper = new QueryWrapper<>();
    // 需求: 查询dept_id 为null 员工信息
    // SELECT id,name,password,email,age,admin,dept_id FROM employee WHERE (dept_id IS NULL)
    // wrapper.isNull("dept_id");

    // 需求: 查询dept_id 为不为null 员工信息
    // SELECT id,name,password,email,age,admin,dept_id FROM employee WHERE (dept_id IS NOT NULL)
    wrapper.isNotNull("dept_id");
    employeeMapper.selectList(wrapper);
}

// 需求: 查询id为1, 2 的员工信息
// SELECT id,name,password,email,age,admin,dept_id FROM employee WHERE (id IN (?,?))
@Test
public void testIn() {
    QueryWrapper<Employee> wrapper = new QueryWrapper<>();
    wrapper.in("id", 1, 2);
    employeeMapper.selectList(wrapper);
}

// 需求: 查询id不为1, 2 的员工信息
// SELECT id,name,password,email,age,admin,dept_id FROM employee WHERE (id NOT IN (?,?))
@Test
public void testNotIn() {
    QueryWrapper<Employee> wrapper = new QueryWrapper<>();
    wrapper.notIn("id", 1, 2);
    employeeMapper.selectList(wrapper);
}

// 需求: 查询id为1, 2 的员工信息
// SELECT id,name,password,email,age,admin,dept_id FROM employee WHERE (id IN (1,2))
@Test
public void testInSql() {
    QueryWrapper<Employee> wrapper = new QueryWrapper<>();
    wrapper.inSql("id", "1,2");
    employeeMapper.selectList(wrapper);
}

// 需求: 查询id不为1, 2 的员工信息
// SELECT id,name,password,email,age,admin,dept_id FROM employee WHERE (id NOT IN (1, 2))
@Test
public void test() {
    QueryWrapper<Employee> wrapper = new QueryWrapper<>();
    wrapper.notInSql("id", "1, 2");
    employeeMapper.selectList(wrapper);
}

模糊查询

like、notLike:匹配值是否包含指定字符串,会自动拼接百分号

likeLeft:%拼在左边

likeRight:%拼在右边

// 需求: 查询name中含有re字样的员工
// SELECT id,name,password,email,age,admin,dept_id FROM employee WHERE (name LIKE ?)
@Test
public void testLike() {
    QueryWrapper<Employee> wrapper = new QueryWrapper<>();
    // wrapper.like("name", "re");     // %re%,会自动拼接百分号
    // wrapper.likeLeft("name", "re");     // %re,left指百分号拼接在左边
    wrapper.likeRight("name", "re");        // re%,right指百分号拼接在右边
    employeeMapper.selectList(wrapper);
}

// 需求: 查询name中不含有fei字样的员工
// SELECT id,name,password,email,age,admin,dept_id FROM employee WHERE (name NOT LIKE ?)
@Test
public void testNotLike() {
    QueryWrapper<Employee> wrapper = new QueryWrapper<>();
    wrapper.notLike("name", "re");
    employeeMapper.selectList(wrapper);
}

逻辑运算符

or

and:链式操作默认用and拼接

注意优先级问题

// 需求: 查询age = 18 或者 name=regex 或者 id =1 的用户
// SELECT id,name,password,email,age,admin,dept_id FROM employee WHERE (age = ? OR name = ? OR id = ?)
@Test
public void testOr() {
    QueryWrapper<Employee> wrapper = new QueryWrapper<>();
    wrapper.eq("age", 18).or().eq("name", "regex").or().eq("id", 1);
    employeeMapper.selectList(wrapper);
}

// 需求:查询name含有re字样的,或者 年龄在18到30之间的用户
@Test
public void testOr2() {
    QueryWrapper<Employee> wrapper = new QueryWrapper<>();
    // SELECT id,name,password,email,age,admin,dept_id FROM employee WHERE (name LIKE ? OR age >= ? AND age <= ?)
    // wrapper.like("name", "re").or().ge("age", 18).le("age", 30);

    // SELECT id,name,password,email,age,admin,dept_id FROM employee WHERE (name LIKE ? OR (age >= ? AND age <= ?))
    wrapper.like("name", "re").or(wr -> wr.ge("age", 18).le("age", 30));
    employeeMapper.selectList(wrapper);
}

// 需求:查询name含有re字样的并且 年龄在小于18或者大于30的用户
// SELECT id,name,password,email,age,admin,dept_id FROM employee WHERE (name LIKE ? AND (age < ? OR age > ?))
@Test
public void testAnd() {
    QueryWrapper<Employee> wrapper = new QueryWrapper<>();
    // wrapper.like("name", "re").lt("age", 18).or().gt("age", 30);  // 错误写法
    wrapper.like("name", "re").and(wr -> wr.lt("age", 18).or().gt("age", 30));
    employeeMapper.selectList(wrapper);
}
5.自定义SQL
  • mapper.xml方式:与之前没什么区别

  • 注解方式

    @Select("select * from employee")
    List<Employee> listByXmlSingle();
    @Select("select e.id, e.name, e.password, e.email, e.age, e.admin, d.id d_id, d.name d_name, d.sn d_sn " +
            "from employee e left join department d " +
            "on e.dept_id = d.id")
    @Results({
            @Result(column="d_id", property = "dept.id"),
            @Result(column="d_name", property = "dept.name"),
            @Result(column="d_sn", property = "dept.sn")
    })
    List<Employee> listByXmlJoin();
    
六、通用Service接口
1.传统方式

定义Service接口,实现该接口以及其中的五个抽象方法,在实现类中注入mapper,通过mapper对象调用持久层的CRUD方法。由于在项目中很多地方都需要用到这些CRUD方法,如果采用这种方式的话,会造成很多的代码重复。

2.通用方式
  • 自定义mapper接口,继承BaseMapper<T>

  • 自定义Service接口,并继承 IService<T> 接口

    public interface IEmployeeService extends IService<Employee> {}
    
  • 实现Service接口,并继承 ServiceImpl<M, T>

    ServiceImpl<M, T>

    泛型1:实体类的mapper接口

    泛型2:实体类

    public class EmployeeServiceImpl extends ServiceImpl<EmployeeMapper, Employee> implements IEmployeeService {}
    

自定义接口继承IService接口,则继承了IService接口中的抽象方法,那么在实现类中必然需要实现这些抽象方法,但这些抽象方法太多了,所以就将实现类继承ServiceImpl类,而ServiceImpl类实现了IService接口中的方法,所以实现类就可以简单理解为实现了IService接口中的抽象方法。

3.常用方法
  • getBaseMapper():获取对应 entity 的 BaseMapper

    BaseMapper<Employee> mapper = employeeService.getBaseMapper();
    System.out.println(mapper == employeeMapper);   // true
    
  • getOne(wrapper):根据 Wrapper,查询一条记录,若结果集是多个会抛出异常,可以添加限制条件 wrapper.last(“LIMIT 1”)

    QueryWrapper<Employee> wrapper = new QueryWrapper<>();
    wrapper.last("limit 1");
    employeeService.getOne(wrapper);
    
  • list(wrapper):指定条件查询多个

    QueryWrapper<Employee> wrapper = new QueryWrapper<>();
    wrapper.eq("age", 25);
    employeeService.list(wrapper).forEach(System.out::println);
    
  • page(page, wrapper):分页 + 高级查询

    • 在启动类中配置分页拦截器(如果没有配置,会查询出全部结果)

      // 分页拦截器
      @Bean
      public MybatisPlusInterceptor mybatisPlusInterceptor() {
          MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
          PaginationInnerInterceptor paginationInnerInterceptor = new PaginationInnerInterceptor(DbType.MYSQL);
          paginationInnerInterceptor.setOverflow(true); //合理化
          interceptor.addInnerInterceptor(paginationInnerInterceptor);
          return interceptor;
      }
      
    • 在接口中定义抽象方法

      IPage<Employee> query(EmployeeQuery qo);
      
    • 在实现类中实现抽象方法

      @Override
      public IPage<Employee> query(EmployeeQuery qo) {
          IPage<Employee> page = new Page<>(qo.getCurrentPage(), qo.getPageSize());  //设置分页信息
          QueryWrapper<Employee> wrapper = Wrappers.<Employee>query();  //拼接条件
          return super.page(page,wrapper);
      }
      
    • 进行测试

      // 需求:查询第2页员工信息, 每页显示3条, 按id排序
      // SELECT id,name,password,email,age,admin,dept_id FROM employee LIMIT ?,?
      @Test
      public void testPage2() {
          EmployeeQuery qo = new EmployeeQuery();
          qo.setCurrentPage(2);
          qo.setPageSize(3);
          QueryWrapper<Object> wrapper = Wrappers.query();
          wrapper.orderByAsc("id");
          employeeService.query(qo);
      }
      
4.事务

自定义方法,需要事务管理的则在方法上贴@Transactional注解

mybatis-plus提供的方法,底层已经对需要事务管理的方法贴了@Transactional注解

  • 5
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
Mybatis-Plus 中,SQL 的解析是通过内置的 SQL 解析器来实现的。Mybatis-Plus 使用了 Mybatis 的核心组件和功能,包括 SQL 解析、参数处理、SQL 执行等。 具体的 SQL 解析流程如下: 1. Mybatis-Plus 会通过 `SqlParserUtils` 工具类创建一个 SQL 解析器对象 `SqlParser`。 2. 在执行 SQL 之前,Mybatis-Plus 会调用 `SqlParser` 的 `processSelect` 方法进行解析。该方法会解析 SQL 中的查询字段、表名、条件等信息,并返回一个 `SqlInfo` 对象。 3. `SqlInfo` 对象中包含了解析后的 SQL 语句、参数映射等信息,可以通过该对象获取解析后的 SQL 语句和参数。 4. Mybatis-Plus 将解析后的 SQL 语句和参数传递给 Mybatis 的执行引擎,通过 `SqlSession` 执行 SQL。 需要注意的是,Mybatis-PlusSQL 解析器仅对内置的基本查询方法进行解析,如 `selectById`、`selectList`、`selectPage` 等。对于自定义的 SQL 语句或使用 Mybatis 的 XML 映射文件,则需要手动编和解析 SQL。 此外,Mybatis-Plus 还提供了一些钩子函数和扩展点,可以自定义 SQL 解析和处理的逻辑。例如,可以实现 `ISqlParser` 接口来自定义 SQL 解析器,实现 `ISqlInjector` 接口来自定义 SQL 注入器等。 总结起来,Mybatis-Plus 是通过内置的 SQL 解析器来解析 SQL,然后将解析后的 SQL 语句和参数传递给 Mybatis 的执行引擎。希望能够解答你的问题!如果还有其他疑问,请继续提问。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

正则表达式1951

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值