4. 查询投影
- 如果我们只希望返回某些列的数据,而不是所有列的数据,我们可以用SELECT 列1, 列2, 列3 FROM …,让结果集仅包含指定列。这种操作称为【投影查询】
2.lambda表达式查询指定字段
@Test void testGetAll() { //查询投影 //创建LambdaQueryWrapper类对象,并指定泛型 LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<User>(); //lambda表达式查询指定字段 lqw.select(User::getId, User::getAge); //将条件Wrapper<T>类型的参数传入selectList()方法中 List<User> userList = userDao.selectList(lqw); System.out.println(userList); }
- 运行结果
- 如果使用的不是lambda表达式,就需要手动指定字段
@Test void testGetAll() { //查询投影 //创建QueryWrapper类对象,并指定泛型 QueryWrapper<User> lqw = new QueryWrapper<User>(); //非lambda表达式查询指定字段 lqw.select("age", "id", "password"); //将条件Wrapper<T>类型的参数传入selectList()方法中 List<User> userList = userDao.selectList(lqw); System.out.println(userList); }
- 运行结果
- 聚合查询 selectMaps()(count、max、min、avg、sum)
@Test void testGetAll() { //查询投影 //创建QueryWrapper类对象,并指定泛型 QueryWrapper<User> lqw = new QueryWrapper<User>(); //聚合查询(count、max、min、avg、sum),lambda无法做聚合查询 //as 起别名 //查询表中有多少条记录 lqw.select("count(*) as count"); //将条件Wrapper<T>类型的参数传入selectMaps()方法中 List<Map<String, Object>> userList = userDao.selectMaps(lqw); System.out.println(userList); }
- 运行结果(结果集 Map 中 count 是 key, 4 是value)
- 分组查询( gruopBy() )
@Test void testGetAll() { //查询投影 //创建QueryWrapper类对象,并指定泛型 QueryWrapper<User> lqw = new QueryWrapper<User>(); //分组查询(groupby) //as 起别名 //按电话分组并分别计数 lqw.select("count(*) as count, tel"); lqw.groupBy("tel"); //将条件Wrapper<T>类型的参数传入selectMaps()方法中 List<Map<String, Object>> userList = userDao.selectMaps(lqw); System.out.println(userList); }
- 运行结果
- 模糊查询(like)
@Test void testGetAll() { LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<User>(); //模糊匹配 like, Left 和 Right指的是%在左边还是右边 lqw.likeRight(User::getName,"J"); List<User> userList = userDao.selectList(lqw); System.out.println(userList); }
5.映射匹配兼容性(@TableField()和@TableName())
- 问题一 :表字段与编码属性设计不匹配
- 如图表字段为 ‘pwd’ ,而实体类为 ‘password’,查询会出现异常,可以在实体类中通过 @TableField(value = “pwd”) 注解将实体类属性与表名进行映射匹配
- 问题二 :编码中添加了数据库中未定义的属性
如图,实体类中有用于判断用户是否在线的online属性,而数据库中没有相应的字段,查询会出现异常,可以通过 @TableField(exist = false) 设置该属性在数据库中不存在
- 问题三 :采用默认查询开发了更多字段查看权限
如图,用户密码默认在查询字段中,而该字段并不随便对外开放,可以用**@TableField(select = false)**将该字段的查询权限关闭
- 问题四 :表名与编码开发设计不同步
可以通过 @TableName(“tbl_user”) 注解将实体类名与数据库表名关联起来
6.id生成策略(@TableId()或全局配置)
- Mybatis-plus提供了多种主键生成策略, 可以在Pojo类中主键上加注解进行配置,例如数据库主键自增 @TableId(type=IdType.AUTO)
- 不同的表应用不同的id生成策略:
日志:自增(1,2,3,4,……) 购物订单:特殊规则(FQ23948AK3843) 外卖单:关联地区日期等信息(10 04 20200314 34 91) 关系表:可省略id ……
- 策略种类
- 全局配置id生成策略
假设我们希望默认全部都使用 AUTO 策略(数据库ID自增),那么可以在 application.yml 中添加如下配置进行修改:
mybatis-plus.global-config.db-config.id-type=auto
7.多数据操作(_BatchIds())
- 应用场景
购物车删除多条记录 - 在testSave()方法中添加两条新纪录,效果如图
- 删除多条记录( deleteBatchIds ( Collection<> ) )
- 代码
@Test void testDelete(){ //删除指定多条数据 List<Long> list = new ArrayList<>(); list.add(12L); list.add(13L); userDao.deleteBatchIds(list); }
- 运行结果
- 查询多条记录
- 代码
- 运行结果
六、CRUD进阶开发II
1.逻辑删除( @TableLogic() 或者 全局配置)
- 应用场景
- 假如编号为1的员工辞职了,他的姓名,工号等信息要删除,但是他工作的合同编号,成交日期,金额等信息需要保留,如果直接执行按id删除操作,会把所有相关的数据删除掉,逻辑删除可以解决这个问题。
- 逻辑删除指的是修改数据的某个字段,使其表示为已删除状态,而非删除数据,保留该数据在数据库中,但是查询时不显示该数据(查询时过滤掉该数据)。
- 在navicat中右键user表,点击设计表选项添加字段delete, 并设置默认值为0,代表未进行逻辑删除,然后点击保存
3.在对应的user实体类中添加逻辑删除字段 deleted , 并通过 @TableLogic() 注解设置未进行逻辑删除的值 value 和 逻辑删除的值 delval
//lombok @Data @TableName("user") public class User { //设置主键生成策略 @TableId(type = IdType.ASSIGN_ID) private Long id; private String name; @TableField(value = "pwd",select = false) private String password; private Integer age; private String tel; //逻辑删除字段,标记当前记录是否被删除 @TableLogic(value = "0" ,delval = "1") private Integer deleted; }
- 在测试类中的 testDelete() 方法方法中删除id为1的记录
- 代码
@Test void testDelete(){ //模拟逻辑删除 userDao.deleteById(1L); }
- 运行结果
从控制台输出以及表更新后的情况来看,可以知道逻辑删除做的其实是更新操作,并且此时查询全部不设置条件会默认查询 逻辑删除字段 deleted = 0(自定义的值)的记录
- 在全局配置中配置逻辑删除相关信息
- 在注解中的字符串里配置容易出错,我们可以在全局配置文件中配置逻辑删除的相关参数
- MyBatisPlus全局配置示例
global-config: db-config: #全局配置逻辑删除字段名 logic-delete-field: deleted #逻辑已删除值(默认1) logic-delete-value: 1 #逻辑未删除值(默认0) logic-not-delete-value: 0