mybatis-plus入门案例

MyBatis-plus是什么?

要解释Mybatis-plus那就必须先解释什么是mybatis:

(1)Mybatis 是一个半 ORM(对象关系映射)框架,它内部封装了 JDBC,开发时只需要关注 SQL 语句 本身,不需要花费精力去处理加载驱动、创建连接、创建 statement 等繁杂的过程。程序员直接编写原生 态 sql,可以严格控制 sql 执行性能,灵活度高。

(2)MyBatis 可以使用 XML 或注解来配置和映射原生信息,将 POJO 映射成数据库中的记录,避免了 几乎所有的 JDBC 代码和手动设置参数以及获取结果集。

(3)通过 xml 文件或注解的方式将要执行的各种 statement 配置起来,并通过 java 对象和 statement 中 sql 的动态参数进行映射生成最终执行的 sql 语句,最后由 mybatis 框架执行 sql 并将结果映射为 java 对象并返回。(从执行 sql 到返回 result 的过程)。

看到这里大概了解了什么是mybatis,那么Mybatis-plus其实就是在mybatis只做增强,不做改变的增强框架,是中国人写的一个非常牛批的框架。这个框架让我们的开发更加简单,我们只需要在项目中添加相关依赖,在服务层实现一下接口就好了,这样一来减少了很多的SQL语句的编写,从而大大提高了开发效率。

mybatis-plus的入门案例

添加依赖
  <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.4.3</version>
        <relativePath/>
  </parent>

    <dependencies>
        <!--mybatis-plus-->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.4.0</version>
        </dependency>
        
        <!--springboot-test-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
        </dependency>
        
		<!--druid-->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid-spring-boot-starter</artifactId>
            <version>1.1.17</version>
        </dependency>
        
		<!--mysql-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.22</version>
        </dependency>
        
        <!--lombok-->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.16</version>
            <scope>provided</scope>
        </dependency>
    </dependencies>
application.properties
#新版本的mysql要设置时区,否则会报错,serverTimezone=GMT%2B8
spring.datasource.url=jdbc:mysql:///mybatis-plus?useUnicode=true&characterEncoding=utf8&serverTimezone=GMT%2B8

spring.datasource.username=root
spring.datasource.password=admin
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver

# 配置slq打印日志
logging.level.cn.wolfcode.mp.mapper=info
Employee实体类
@Setter
@Getter
@ToString
//表名注解:指定当前实体类映射哪张数据库表, 默认是跟实体类名一致
@TableName("t_employee")
public class Employee {
    //主键注解:标记当前属性映射表主键。IdType.AUTO表示数据库ID自增
    @TableId(value = "id",type = IdType.AUTO)
    private Long id;
    //字段注解:指定当前属性映射数据库表哪一列, 默认是跟属性名一致
    @TableField("name")
    private String username;
    private String password;
    private String email;
    private int age;
    private int admin;
    private Long deptId;
}
EmployeeMapper

问题:没有编写crud的SQL语句,却可以执行crud操作?

思考:对mysql数据库中的数据进行crud肯定都需要依赖SQL,而代码中没有编写SQL语句,那么可以肯定mybatis-plus帮我们编写了

<!-- 以查询为例:selectById(1L)  要实现查询功能:必须拼接处SQL与条件 -->
<!--拼接SQL-->
select id,name,password......from employee
<!--条件参数-->
id:1L

mybatis-plus是如何实现上面操作:

​ 1.spring容器启动后,Mybatis-plus就开始解析EmployeeMapper上面指定泛型类:Employee

​ 2.通过反射解析Employee类,得到:

​ 类名---->作为SQL 表名

​ 属性---->作为SQL 列名

​ 3.将解析出来的数据,根据调用的方法拼接处不同的SQL语句,然后执行

public interface EmployeeMapper extends BaseMapper<Employee> {
}
@Service
@Transactional
public class EmployeeServiceImpl extends ServiceImpl<EmployeeMapper, Employee> implements IEmployeeService {
 
}
测试类代码:
//这里使用springboot的测试
@SpringBootTest
class EmployeeMapperTest {
    @Autowired
    private IEmployeeService employeeService;

    @Test
    public void save(){
        Employee employee = new Employee();
        employee.setName("James");
        employee.setPassword("23");
        employeeService.save(employee);
    }

    @Test
    public void deleteById(){
        employeeService.removeById(21);
    }

    @Test
    public void update(){
        Employee employee = new Employee();
        employee.setId(21L);
        employee.setName("Davis");
        employee.setPassword("33");
        employeeService.updateById(employee);
    }

    @Test
    public void queryById(){
        System.out.println(employeeService.getById(1));
    }
}

通用mapper

使用建议:

知道id,并且所有更新使用字段updateById

注意:如果实体类中有基本数据类型,且更新时有默认值,mybatis-plus会认为他不为空,然后把数据库对应的列修改成了这个默认值

updateById

public void testUpdate1(){
      Employee employee = new Employee();
      employee.setId(3L);
      employee.setName("dafei3");
      employee.setPassword("123");
      employee.setEmail("dafei3@xx.com");
      employee.setAge(18);
      employee.setAdmin(1);
      employee.setDeptId(2L);
      employeeMapper.updateById(employee);
}

部分字段更新,使用update:

用法:wrapper.条件.set需要更新的字段

update

//修改id为1的员工名字为James,password为789
public void testUpdate2(){
        UpdateWrapper<Employee> wrapper = new UpdateWrapper<>();
        wrapper.eq("id",1L)
                .set("name","James")
                .set("password","789");
        employeeMapper.update(null,wrapper);
}

删除如何选用:

根据Id删除员工

deleteById

//需求:删除Id为3的员工
@Test
public void testDeleteById(){
    employeeMapper.deleteById(3L)
}

根据满足一到多个条件的才删除

deleteByMap

//需求:删除name=李六明并且age=25的员工信息
@Test
public void testDeleteByMap(){
    HashMap map = new HashMap();
    map.put("name","李六明");
    map.put("age",25);
    employeeMapper.deleteByMap(map);
}

根据满足一到多个条件的才删除

delete

//需求:删除name=dafei并且age=18的员工信息
//delete from employee where name ='dafei' and age=18
@Test
public void testDeleteWrapper(){
    QueryWrapper<Employee> wrapper = new QueryWrapper<>();
    wrapper.eq("name","xiaofei").eq("age",18);
    employeeMapper.delete(wrapper);
}

批量删除

deleteBatchIds

//删除id为17 或 18 的员工
//delete from employee where id in(17,18)
@Test
public void testDeleteBatchIds(){
    employeeMapper.deleteBatchIds(Arrays.asList(17,18));
}

根据Id查询

selectById

//需求:查询id为1的员工所有信息
//select * from employee where id= 1
@Test
public void testSelectById(){
     System.out.println(employeeMapper.selectById(1));
}

批量查询

SelectBatchIds

//需求:查询id为4 或 5 或 6的员工所有信息
//select * from employee where id in(4,5,6)
@Test
public void testSelectBatchIds(){
    System.out.println(employeeMapper.selectBatchIds(Arrays.asList(4,5,6)));
}

满足一个到多个条件才删除

selectByMap

//需求:查询name= James and  age=40的员工信息
//select * from employee where name= 'James' and  age=40
@Test
public void testSelectByMap(){
     HashMap map = new HashMap();
     map.put("name","James");
     map.put("age",40);
    System.out.println(employeeMapper.selectByMap(map));
}

查询满足某些条件的数据条数

selectCount

//需求: 查询满足(name = James)条件的所有的员工个数
@Test
public void testSelectCount(){
    QueryWrapper<Employee> wrapper = new QueryWrapper<>();
    wrapper.eq("name","James");
    System.out.println(employeeMapper.selectCount(wrapper));
}

查询满足某些条件的所有数据的集合(类型是:Employee)

selectList

//需求: 查询满足(name = James)条件的所有的员工
@Test
public void testSelectList(){
    QueryWrapper<Employee> wrapper = new QueryWrapper<>();
    wrapper.eq("name","James");
    System.out.println(employeeMapper.selectList(wrapper));
}

查询满足某些条件的所有数据的集合(类型是:Map<String, Object>)

selectMaps

应用场景:联表高级查询

//需求:查询满足条件的所有的员工信息, 返回List<Map<String, Object>>  底层将每条数据封装成HashMap
//SELECT id,name,age FROM employee WHERE (name = ?)
@Test
public void testSelectMaps(){
    QueryWrapper<Employee> wrapper = new QueryWrapper<>();
    wrapper.eq("name","James");
    wrapper.select("id,name,age");
    List<Map<String, Object>> list = employeeMapper.selectMaps(wrapper);
    list.forEach(System.out::println);
}

分页查询

selectPage

应用场景:单表分页高级查询

注意:在使用分页功能之前,一定要记得在启动类中配置好分页拦截器(MybatisPlusInterceptor),否则不起作用

@Test
public void testSelectPage(){
    QueryWrapper<Employee> wrapper = new QueryWrapper<>();
    //参数1:当前页, 参数2:每页显示条数
    IPage<Employee> page = new Page<>(1, 3);
    employeeMapper.selectPage(page, wrapper);

    System.out.println("当前页:" + page.getCurrent());
    System.out.println("每页显示条数:" + page.getSize());
    System.out.println("总页数:" + page.getPages());
    System.out.println("总数:" + page.getTotal());
    System.out.println("当前页数据:" + page.getRecords());
}

分页查询

selectMapsPage

应用场景:联表分页高级查询,等价于resultMap的使用

注意:在使用分页功能之前,一定要记得在启动类中配置好分页拦截器(MybatisPlusInterceptor),否则不起作用

//需求:查询第二页员工数据, 每页显示3条, (分页返回的数据是HashMap)
@Test
public void testSelectMapsPage(){
    QueryWrapper<Employee> wrapper = new QueryWrapper<>();

    IPage<Map<String, Object>> page = new Page<>(2,3);
    employeeMapper.selectMapsPage(page, wrapper);

    System.out.println("当前页:" + page.getCurrent());
    System.out.println("每页显示条数:" + page.getSize());
    System.out.println("总页数:" + page.getPages());
    System.out.println("总数:" + page.getTotal());
    System.out.println("当前页数据:" + page.getRecords());
}

条件构造器

updateWrapper.set(“age”,18)

UpdateWrapper

该方法 等价于SQL片段: “set age = ?” =>paramter : 18 , 使用了占位符

//UpdateWrapper更新
//需求:将id=1的员工age改为18
    @Test
    public void testUpdate(){
        UpdateWrapper<Employee> wrapper = new UpdateWrapper<>();
        wrapper.set("age",18).eq("id",1L);
        employeeMapper.update(null,wrapper);
    }
LambdaUpdateWrapper
//LambdaUpdateWrapper更新
//需求:将id=1的员工age改为18
@Test
public void testLambdaUpdate1(){
    LambdaUpdateWrapper<Employee> wrapper = new LambdaUpdateWrapper<>();
    wrapper.eq(Employee::getId,1L)
            .set(Employee::getAge,18);
    employeeMapper.update(null,wrapper);
}

updateWrapper.setSql(“name =‘dafei’”)

该方法 等价于SQL片段: “name = ‘dafei’” 没有使用了占位符

//需求:将id=1的用户name改为dafei
@Test
public void testUpdate3(){
    UpdateWrapper<Employee> wrapper = new UpdateWrapper<>();
    wrapper.eq("id",1L);
    wrapper.setSql("name ='dafei'");
    employeeMapper.update(null,wrapper);
}

queryWrapper.select(“name”,“age”);

使用select方法指定需要查询的列,如果不设置会默认查询全部列(select *)

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

queryWrapper.orderByAsc(“age”)

按照员工年龄age正序排序,如果age一样, 按id正序排

//需求:查询所有员工信息按age正序排, 如果age一样, 按id正序排
@Test
public void testQuery3(){
    QueryWrapper<Employee> wrapper = new QueryWrapper<>();
    wrapper.orderByAsc("age").orderByAsc("id");
    List<Employee> employees = employeeMapper.selectList(wrapper);
    employees.forEach(System.out::println);
}

queryWrapper.orderByDesc(“id”)

按照员工年龄age正序排序, 如果age一样, 按id倒序排序

//需求:查询所有员工信息按age正序排, 如果age一样, 按id倒序排序
@Test
public void testQuery5(){
    QueryWrapper<Employee> wrapper = new QueryWrapper<>();
    wrapper.orderByAsc("age");
    wrapper.orderByDesc("id");
    List<Employee> employees = employeeMapper.selectList(wrapper);
    employees.forEach(System.out::println);
}
优先级:优先级从上往下

queryWrapper.eq(“name”,“dafei”)

等价于: “where name=‘dafei’”

多个eq连用等价于 加了and关键字 :WHERE (name = “dafei” AND age = 18)

//需求:查询name=dafei, age=18的员工信息
//SELECT * FROM employee WHERE (name = ? AND age = ?)
@Test
public void testQuery6(){
    QueryWrapper<Employee> wrapper = new QueryWrapper<>();
    wrapper.eq("name","dafei");
    wrapper.eq("age",18);
    List<Employee> employees = employeeMapper.selectList(wrapper);
    employees.forEach(System.out::println);
}

queryWrapper.allEq(map)

使用map存放需要过滤的条件,并传入map对象调用allEq(全等)方法,查询满足map中所有条件的数据集合,该方法底层调用了另一个方法allEq(params, true),这里有个默认值为true,意思是如果当前key的value为null时会自动调用isNull方法。相反,如果自动设置为false的话,当前key的value为null时,该条件不会加到sql语句中去。

例1: allEq({id:1,name:“老王”,age:null})—>id = 1 and name = ‘老王’ and age is null

例2: allEq({id:1,name:“老王”,age:null}, false)—>id = 1 and name = ‘老王’

//需求:查询name=dafei, age=18的员工信息
//SELECT * FROM employee WHERE (name = ? AND dept_id IS NULL AND age = ?)
@Test
public void testQuery7(){
    QueryWrapper<Employee> wrapper = new QueryWrapper<>();
    Map<String,Object>map = new HashMap<>();
    map.put("name","dafei");
    map.put("age",18);
    map.put("dept_id", null);
    wrapper.allEq(map);
    List<Employee> employees = employeeMapper.selectList(wrapper);
    employees.forEach(System.out::println);
}
//需求:查询name=dafei, age=18的员工信息
//SELECT * FROM employee WHERE (name = ? AND age = ?)
@Test
public void testQuery8(){
    QueryWrapper<Employee> wrapper = new QueryWrapper<>();
    Map<String,Object>map = new HashMap<>();
    map.put("name","dafei");
    map.put("age",18);
    map.put("dept_id", null);
    wrapper.allEq(map,false);
    List<Employee> employees = employeeMapper.selectList(wrapper);
    employees.forEach(System.out::println);
}

queryWrapper.ne(“name”,“dafei”)

查询name != dafei员工信息

//需求:查询name != dafei员工信息
@Test
public void testQuery11(){
    QueryWrapper<Employee> wrapper = new QueryWrapper<>();
    wrapper.ne("name","dafei");
    System.out.println(employeeMapper.selectList(wrapper));
}

queryWrapper.gt(“age”,18)

查询age 大于18岁员工信息

//需求:查询age 大于18岁员工信息
@Test
public void testQuery12(){
    QueryWrapper<Employee> wrapper = new QueryWrapper<>();
    wrapper.gt("age",18);
    System.out.println(employeeMapper.selectList(wrapper));
}

queryWrapper.lt(“age”,30)

查询age 小于18岁员工信息

//需求:查询age 小于30岁员工信息
@Test
public void testQuery12(){
    QueryWrapper<Employee> wrapper = new QueryWrapper<>();
    wrapper.lt("age",30);
    System.out.println(employeeMapper.selectList(wrapper));
}

queryWrapper.ge(“age”,18)

查询age 大于等于18岁员工信息

//需求:查询age 大于等于18岁员工信息
@Test
public void testQuery12(){
    QueryWrapper<Employee> wrapper = new QueryWrapper<>();
    wrapper.ge("age",18);
    System.out.println(employeeMapper.selectList(wrapper));
}

queryWrapper.le(“age”,30)

查询age 小于等于30岁员工信息

//需求:查询age 小于等于30岁员工信息
@Test
public void testQuery12(){
    QueryWrapper<Employee> wrapper = new QueryWrapper<>();
    wrapper.le("age",30);
    System.out.println(employeeMapper.selectList(wrapper));
}

queryWrapper.isNull(“dept_id”)

查询dept_id 为null 员工信息

//需求: 查询dept_id 为null 员工信息
@Test
public void testQuery15(){
    QueryWrapper<Employee> wrapper = new QueryWrapper<>();
    wrapper.isNull("dept_id");
    System.out.println(employeeMapper.selectList(wrapper));
}

queryWrapper.isNotNull(“dept_id”)

查询dept_id 不为null 员工信息

//需求: 查询dept_id 为null 员工信息
@Test
public void testQuery15(){
    QueryWrapper<Employee> wrapper = new QueryWrapper<>();
    wrapper.isNotNull("dept_id");
    System.out.println(employeeMapper.selectList(wrapper));
}

queryWrapper.in(“id”,1,2)

查询id为1, 2 的员工信息,这种方式使用了占位符

//需求: 查询id为1, 2 的员工信息
@Test
public void testQuery17(){
    QueryWrapper<Employee> wrapper = new QueryWrapper<>();
    wrapper.in("id",1,2);
    System.out.println(employeeMapper.selectList(wrapper));
}

queryWrapper.in(“id”,“1,2”)

查询id为1, 2 的员工信息,这种方式没有使用了占位符,是sql片段,一般推荐使用上面那种方式,可以防止sql注入

//需求: 查询id为1, 2 的员工信息
@Test
public void testQuery18(){
    QueryWrapper<Employee> wrapper = new QueryWrapper<>();
    wrapper.inSql("id","1,2");
    System.out.println(employeeMapper.selectList(wrapper));
}

queryWrapper.like(“name”,“fei”)

查询name中含有fei字样的员工

//需求: 查询name中含有fei字样的员工
@Test
public void testQuery19(){
    QueryWrapper<Employee> wrapper = new QueryWrapper<>();
    wrapper.like("name","fei");
    System.out.println(employeeMapper.selectList(wrapper));
}

queryWrapper.notLike(“name”,“fei”)

查询name中不含有fei字样的员工

//需求: 查询name中不含有fei字样的员工
@Test
public void testQuery20(){
    QueryWrapper<Employee> wrapper = new QueryWrapper<>();
    wrapper.notLike("name","fei");
    System.out.println(employeeMapper.selectList(wrapper));
}

queryWrapper.likeLeft(“name”,“fei”)

查询name以fei结尾的员工信息 等价于 like “%fei”

//需求: 查询name以fei结尾的员工信息
@Test
public void testQuery21(){
    QueryWrapper<Employee> wrapper = new QueryWrapper<>();
    wrapper.likeLeft("name","fei");
    System.out.println(employeeMapper.selectList(wrapper));
}

queryWrapper.likeRight(“name”,“fei”)

查询姓王的员工信息 等价于 like “王%”

	//需求: 查询姓王的员工信息
    @Test
    public void testQuery22(){
        QueryWrapper<Employee> wrapper = new QueryWrapper<>();
        wrapper.likeRight("name","王");
        System.out.println(employeeMapper.selectList(wrapper));
    }

queryWrapper.or()

等价于 or关键字

//需求: 查询age = 18 或者 name=dafei 或者 id =1 的用户
@Test
public void testQuery23(){
    QueryWrapper<Employee> wrapper = new QueryWrapper<>();
    wrapper.eq("age",18)
            .or()
            .eq("name","dafei")
            .or()
            .eq("id",1);
    System.out.println(employeeMapper.selectList(wrapper));
}

queryWrapper.and()

等价于 and关键字

//需求:查询name含有fei字样的并且 年龄在小于18或者大于30的用户
@Test
public void testQuery26(){
    QueryWrapper<Employee> wrapper = new QueryWrapper<>();
    wrapper.like("name", "fei")
            .and(wr->wr.le("age",18)
                    .or()
                    .ge("age",30));
    System.out.println(employeeMapper.selectList(wrapper));
}

queryWrapper.groupBy(“dept_id”)

以部门id进行分组查询,查每个部门员工个数

select 后面的列只能是 group by 后面中的列

//需求: 以部门id进行分组查询,查每个部门员工个数
@Test
public void testQuery27(){
    QueryWrapper<Employee> wrapper = new QueryWrapper<>();
    wrapper.select("id","count(*) count");
    wrapper.groupBy("dept_id");
    System.out.println(employeeMapper.selectList(wrapper));
}

queryWrapper.having(“count > {0}”,3)

这里的{0}是占位符

以部门id进行分组查询,查每个部门员工个数, 将大于3人的部门过滤出来

//需求: 以部门id进行分组查询,查每个部门员工个数, 将大于3人的部门过滤出来
@Test
public void testQuery28(){
    QueryWrapper<Employee> wrapper = new QueryWrapper<>();
    wrapper.select("id","count(*) count");
    wrapper.groupBy("dept_id");
    wrapper.having("count > {0}",3);
    System.out.println(employeeMapper.selectMaps(wrapper));
}

通用方式

1:自定义服务接口集成IService接口
public interface IEmployeeService extends IService<Employee> {

}


/*2:服务接口实现类集成IService接口实现类ServiceImpl同时实现自定义接口
注意ServiceImpl实现类泛型:
泛型1:实体类的mapper接口
泛型2:实体类*/

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

}
上一篇:mybatis plus 写sql语句


下一篇:mybtais-plus学习--BaseMapper提供的方法及SQL语句生成