MyBatis-Plus 总结

MyBatis-Plus

1: mybatis-plus 常用注解
2: mybatis-plus 通用 mapper 接口方法
	1>编写方式[必须掌握]
3: 条件构造器 QueryWrapper UpdateWrapper

4: 高级查询 
	里面各种条件查询必须会
    1>投影
    2>排序
    3>分组
    4>条件查询
    5>自定义 sql
    
5: 通用 service接口

MyBatis-plus 是一个 MyBatis 的增强工具

mapper接口 继承 BaseMapper<当前实体类>

mybatis-plus mapper 编写规则:
1. 自定义一个mapper接口
2. 接口继承BaseMapper接口
3. BaseMapper接口明确指定要操作的实体对象泛型: Employee

问题1 : EmployeeMapper 接口并没有编写crud 方法, 为什么测试类中可以直接使用

EmployeeMapper 接口继承 BaseMapper 接口, 可以继承 BaseMapper接口中所有crud 方法

问题2 : 项目中并没有编写EmployeeMapper.xml 也没有crud sql 编写操作, 为啥就可以进行crud 操作呢?

项目没写, 但是 mybatis-plus 框架帮忙写了, 引申出一个问题: mybatis-plus怎么编写crud sql 语句的?

以查询所有数据为例子:
	接口方法: employeeMapper.selectList(...)
	执行sql: SELECT id,name,password,age,admin,dept_id FROM employee
	思考: 如何查询上述查询 sql?
	
	分析发现:
	sql语句中表名跟domain中类名一致
	sql语句中列名跟domain中字段名一致
	
	最终原理:
	  mybatis-plus 启动之后会获取 BaseMapper 接口中指定的泛型类型,通过这个类型字节码对象 反射内省得到该实体对象的类名, 字段名,
	   进而拼接出 表名 与 列名, 那么 sql 语句就出来了

mybatis-plus注解

// 当前这个字段映射name对象
@TableField(value = "") 
//mybatis-plus 会自动的将 dept_id 中的_转换为java中驼峰命名方式
private Long deptId;
// 不将当前字段作为表的列映射
@TabelField(exist = false)

当表名 与 实体类的名称不一致的时候
    // 当前类名映射 t_employee 这张表
    @TableName("t_employee")
    
如果 实体类中的 id 与 表中的 id不一致
  @TableField(value = "id")
    // 或
  @TableId(type=IdType.AUTO) // 指定id操作策略 数据库自增

添加操作(insert)

mybatis-plus 做添加的时候, 如果 实体类属性值为 null, 不会将该属性作为 insert sql 中的列

修改操作(update)

updateById

// updateById
UPDATE employee SET name=?, age=?, admin=? where id=?

拼接sql规则 :
  1> 传入参数(实体)对象如果属性值为null, 那么该属性不参与sql 列拼接
  2> 如果参数(实体)对象属性为基本属性, 它们有默认值, mybatis-plus就认为
  是属性值不为 null ,这些属性会参与 sql 列拼接 
      
问 : 如果不想让只有默认值得基本属性参与sql列拼接怎么办?
    方式1: 将基本属性字段设置为包装类型
    方式2: 使用 BaseMapper中的 update(null,wrapper)

update( 实体类 / null ,wrapper)

// update(employee,wrapper);
这种写法是 update 方法中其中一种操作方式, update 数据从传入的 employee 实体中获取
    
employee.setAge(18);
employee.setName("dafei");
    // 暂时理解where 条件 sql 片段: name=dafei
UpdateWrapper<Employee> wrapper = Updatenew Wrapper<>();
wrapper.eq("name","dafei");
employeeMapper(Employee,wrapper);


// update(null,wrapper);
这种用法 : 实体对象设置为 null ,更新数据与条件从wrapper 获取[部分字段更新方式]
 UpdateWrapper<Employee> wrapper = new UpdateWrapper<>();
 wrapper.eq("name","dafei");
 wrapper.set("age",18);
 employeeMapper.update(null,wrapper);

updateById 与 update 的使用范围

updateById
    使用范围:
1> update 的实体对象必须有id值
2> 全字段(全量) 更新
    
update
    适用范围:
1> update数据筛选条件不仅仅是 id
2> 部门字段更新

删除操作

deleteById

Long 继承 Number, Number 实现 Serializable 序列化接口

deleteBatchIds

批量删除
    employeeMapper.deleteBatchIds(Arrays.asList(21L,22L));
sql语句:
	delete form employee where id in(?,?)

deleteByMap

map = new HashMap<>();
map.put(key,value);
// key : 条件列 , value : 条件值
SQL语句:
	 delete from employee where name = ? and age =?

delete(wrapper)

// 与 updateWrapper 一样, 区别: 一个update相关(DML), 一个查询相关(DQL)
QueryWrapper<Employee> wrapper = new QueryWrapper<>();
wrapper.eq("","");

查询操作

selectById

 查单个

selectBatchIds

批量查询	
batch方法在mysql 中 等于 in

selectByMap

 以Map为条件

selectCount(wrapper)

查全部count 有多少条数据
	不拼接任何条件 
    返回 Integer 类型

selectList(wrapper / null)

查所有数据

selectMaps(wrapper)

查所有,当返回的值没法用实体对象封装的时候
   返回值 List<Map<String,Object>> mapList
   底层将每条数据封装成HashMap

selectPage

//分页拦截器
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        PaginationInnerInterceptor paginationInnerInterceptor = new PaginationInnerInterceptor(DbType.MYSQL);
        paginationInnerInterceptor.setOverflow(true); //合理化
        interceptor.addInnerInterceptor(paginationInnerInterceptor);
        return interceptor;
    }

//1: 分页拦截器
 在 APP.class  启动类 中 配置一个 分页拦截器
//2: 分页逻辑

// mybatis-plus 分页对象 等价于 PageResult 或者 PageInfo
IPage<Employee> page = new Page<>(current : 当前页 ,size : 每页显示条数);

在这里插入图片描述

条件构造器

父类: AbstractWrapper

更新

使用 UpdateWrapper
@SpringBootTest
public class ControllerTest {
    @Autowired
    private EmployeeMapper employeeMapper;

    /**
     * 需求:将id=1的员工name改为scorpio 会造成数据丢失 因为 age 和
     *  		admin 字段是基本类型 有默认值 0
     *      当进行updateById 的时候 会默认添加进去
     */
    @Test
    public void testUpdate(){
        Employee employee = new Employee();
        employee.setId(1L);
        employee.setName("scorpio");
        employeeMapper.updateById(employee);
    }

    /**
     * 需求:将id=9的员工name改为scorpio
     *      UPDATE employee SET name=? WHERE (id = ?)
     *
     *      wrapper.eq()  表示条件
     *      wrapper.set()   表示修改内容
     */
    @Test
    public void testUpdate2(){
        UpdateWrapper<Employee> wrapper = new UpdateWrapper<>();
        wrapper.eq("id",9L);
        wrapper.set("name","scorpio");
        employeeMapper.update(null,wrapper);
    }


    /**
     *  需求:将id=9的员工age改为20, 如果传入uname变量值不等于null
     * 			或者“”,修改为员工name为uname变量值
     *       UPDATE employee SET age=?,name=? WHERE (id = ?)
     */
    @Test
    public void testUpdate3(){
        String uname = "xxx";
        UpdateWrapper<Employee> wrapper = new UpdateWrapper<>();
        wrapper.eq("id",9L);
        wrapper.set("age",20);
        /*if (StringUtils.hasLength(uname)){
            wrapper.set("name",uname);
        }*/
        // 等价于上面的操作
        wrapper.set(StringUtils.hasLength(uname),"name",uname);
        employeeMapper.update(null,wrapper);
    }

    /**
     * setSql
     * 需求:将id=9的用户name改为scorpio
     *     UPDATE employee SET name='scorpio' WHERE (id = ?)
     */
    @Test
    public void testUpdate4(){
        UpdateWrapper<Employee> wrapper = new UpdateWrapper<>();
        wrapper.eq("id",9L);
        wrapper.setSql("name='scorpio'");// 使用sql 片段 直接插入
        employeeMapper.update(null,wrapper);
    }
}
使用 LambdaUpdateWrapper
    /**
     * LambdaUpdateWrapper
     * 需求:将id=9的用户name改为scorpio
     */
    @Test
    public void testUpdate5(){
        LambdaUpdateWrapper<Employee> wrapper = new LambdaUpdateWrapper<>();
        wrapper.eq(Employee::getId,9L);
        wrapper.set(Employee::getName,"scorpio");
        employeeMapper.update(null,wrapper);
    }
查询操作 QueryWrapper 和 LambdaQueryWrapper
    /**
     * QueryWrapper
     * 需求:查询name=scorpio, age=20的用户
     *  SELECT id,name,password,email,age,admin,dept_id 
     * 		FROM employee WHERE (name = ? AND age = ?)
     */
    @Test
    public void testQuery1(){
        QueryWrapper<Employee> wrapper = new QueryWrapper<>();
        /*wrapper.eq("name","scorpio");
        wrapper.eq("age",20);*/
        // 等价于上面 代码
        wrapper.eq("name", "scorpio").eq("age", 20);
        System.out.println(employeeMapper.selectList(wrapper));

    }

    /**
     * LambdaQueryWrapper
     * 需求:查询name=scorpio, age=20的用户
     *  SELECT id,name,password,email,age,admin,dept_id
     * 		 FROM employee WHERE (name = ? AND age = ?)
     *      
     *      开发中推荐使用
     */
    @Test
    public void testQuery2(){
        LambdaQueryWrapper<Employee> wrapper = new LambdaQueryWrapper<>();
        /*wrapper.eq(Employee::getName,"scorpio");
        wrapper.eq(Employee::getAge,20);*/
        // 等价于上面 代码
        wrapper.eq(Employee::getName, "scorpio").eq(Employee::getAge, 20);
        System.out.println(employeeMapper.selectList(wrapper));

    }

各种 Wrapper 对象的创建

 /**
     * 各种 Wrapper 的创建
     *
     *   public static <T> QueryWrapper<T> query() {
     *         return new QueryWrapper<>();
     *     }
     */
    @Test
    public void testWrappers(){
        // Query
        QueryWrapper<Employee> queryWrapper1 = new QueryWrapper<>();
        QueryWrapper<Employee> queryWrapper2 = Wrappers.<Employee>query();

        LambdaQueryWrapper<Employee> queryWrapper3 = new LambdaQueryWrapper<>();
        LambdaQueryWrapper<Employee> queryWrapper4 = Wrappers.<Employee>lambdaQuery();

        LambdaQueryWrapper<Employee> queryWrapper5 = queryWrapper2.lambda();


        // Update
        UpdateWrapper<Employee> updateWrapper1 = new UpdateWrapper<>();
        UpdateWrapper<Employee> updateWrapper2 = Wrappers.<Employee>update();

        LambdaUpdateWrapper<Employee> updateWrapper3 = new LambdaUpdateWrapper<>();
        LambdaUpdateWrapper<Employee> updateWrapper4 = Wrappers.<Employee>lambdaUpdate();

        LambdaUpdateWrapper<Employee> updateWrapper5 = updateWrapper2.lambda();
    }

高级查询

列投影

wrapper.select("",""); // 列投影: 列表出指定的列, 其他列不查

wrapper.select(" , "); // sql 片段

排序

都是正序
wrapper.orderByAsc("age","id"); // ORDER By age ASC,id ASC

wrapper.orderByAsc("age");	// 正序
wrapper.orderByDesc("id");	// 倒序

// 参数1 : 满足排序条件, 参数2: 排序策略(true:正序,false:倒序)
wrapper.orderBy(true,true,"age");
wrapper.orderBy(true,false,"id");

分组查询

wrapper.select("dept_id","count(id) count");
wrapper.groupBy("dept_id");

// 如果要添加 having 条件
// wrapper.having("count>3");
wrapper.having("count > {0}",3);

// 因为返回的东西不可以直接封装成对象 , 所以 用 selectMaps

条件查询

比较运算符
1.eq("属性名","属性值") :	等于
// 一个eq,一个等 两个eq加起来等  and 操作
		key			value
	sql (name = ? AND age = ?)

2.allEq(map) : 里面传的是个 map数组	全等于
	sql (name = ? AND age = ?)

3.ne : 不等于
    
4.gt : 大于

5.ge : 大于等于

6. lt : 小于

7. le : 小于等于
    
8.between : 某一列大于某个值小于某个值   [n,m]
    
9.notBetween : 某一列不大于某个值也不小于某个值	[n,m]之外
    
10.isNull : 为空 
    wrapper.isNull("name");	// where name is null

11.isNotNull : 不为空
    wrapper.isNotNull("name");	// where name is not null 

12.in : 某列 = ? 或 某列 = ?
    wrapper.in("id",1L,2L);	// id in(1,2)

13.insql : 某列 = ? 或 某列 = ?  		sql片段
    wrapper.insql("id","1,2");	// id in(1,2)

14.notInsql : 某列 != ? 或 某列 != ?
    wrapper.notInsql("id","1,2");	// id not in(1,2)
模糊查询
like : %fei%
    wrapper.like("name","fei");   // 自动拼接 %fei%

notLike : 
	wrapper.like("name","fei");

likeLeft :	'%fei'		以fei结尾
	以 % 判断左右
likeRight : 'fei%'		以fei开头
逻辑运算符
and :// 方式1:
    // mybatis-plus 默认 多条件 下 and连接
    // 如果想要 or 操作 就需要明确调用or方法
   	// 在中间
    wrapper.or();
	
	// 方式2:
	wrapper.lt("age",18).or().gt("age",30);	

or : 或者
    
嵌套 and : 
	wrapper.like("name","fei")
        .and(wr -> wr.lt("age",18).or().gt("age",30))
        // wr 为 变量 随便写 代表第二个wrapper
        
        
    /**
     * 需求:查询name含有hao字样的,和 年龄在18到30之间的用户
     *       WHERE (name LIKE ? AND (age BETWEEN ? AND ?))
     */
    @Test
    public void testQueryANDOR2(){
        QueryWrapper<Employee> wrapper = new QueryWrapper<>();
        wrapper.like("name","hao")
                .and(wr -> wr.between("age",18,30));
        employeeMapper.selectList(wrapper);
    }

自定义Sql ->mapper.xml方式

多表关联查询
多表关联查询时, 可以使用以前 xml 方式进行关联操作
	如果使用 mybatis-plus 该怎么写?
	
mybatis-plus 是没法做多表关联查询: 即无法使用 join, 但支持 额外sql查询
	如果需要关联查询 : 如果采用额外sql 方式, 直接用mybatis-plus编码方式即可 ,如果采用关联查询方式 需要自己写 mapper.xml 文件

@Test
public void testQuery(){
    QueryWrapper<Employee> wrapper = new QueryWrapper<>();
    List<Employee> employees = employeeMapper.selectList(wrapper);
    for (Employee employee : employees) {
        employee.setDept(departmentMapper.selectById(employee.getDeptId()));
    }
    employees.forEach(System.err::println);
}

自定义Sql ->注解方式

@Select4

在这里插入图片描述

通用Service接口

/**
 * mybatis-plus 通用 service 层接口:
 *      1: 自定义 一个业务层 service 层接口 (IEmployeeService)
 *      2: 继承一个通用接口 IService<T> 接口
 *      3: 指定 泛型为 当前 service 的 实体对象(Employee)
 */
public interface IEmployeeService extends IService<Employee> {
}

业务实现类

/**
 * mybatis-plus service 层实现类定义规则:
 *      1>继承一个 ServiceImpl 类
 *      2>指定 两个泛型: 操作实体对象对应mapper接口: EmployeeMapper
 * 			                     操作实体对象 : Employee
 *      3>实现自定义service接口 : IEmployeeService
 */
@Service
public class EmployeeServiceImpl extends ServiceImpl<EmployeeMapper, Employee> implements IEmployeeService {
}
insert == save
updateById == updateById
deleteById == removeById
selectById == getById
selectList == list

实现分页逻辑

service接口

public interface IEmployeeService extends IService<Employee> {
    /**
     * 分页操作
     */
    IPage<Employee> queryPage(EmployeeQueryObject qo);
    
}

service实现类

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

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

测试类

    /**
     * -----------------------分页操作--------------------
     */
    @Test
    public void testPage(){

        EmployeeQueryObject qo = new EmployeeQueryObject();
        qo.setPageSize(3);
        qo.setCurrentPage(2);
        IPage<Employee> page = employeeService.queryPage(qo);

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


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值