赞
踩
1.1.1【Mybatis概念】
问题1:Mybatis是什么,能干嘛?
MyBatis 是一款优秀的 持久层框架,用于简化 JDBC 开发(对jdbc代码进行了封装)
框架:框架就是一个半成品软件,是一套可重用的、通用的、软件基础代码模型
持久层:JavaEE三层架构:表现层、业务层、持久层
问题2:JDBC存在的缺点?
注册驱动、获取连接
SQL语句
操作繁琐
手动设置参数
手动封装结果集
问题3:Mybatis是如何进行规避的?
硬编码可以配置到配置文件
操作繁琐的地方mybatis都自动完成
2.1.1【MyBatisPlus简介】
问题1:MyBatisPlus具体有哪些特性?
MyBatisPlus(简称MP)是基于MyBatis框架基础上开发的增强型工具,旨在简化开发、提高效率
MyBatisPlus特性
无侵入:只做增强不做改变,不会对现有工程产生影响
强大的 CRUD 操作:内置通用 Mapper,少量配置即可实现单表CRUD 操作
支持 Lambda:编写查询条件无需担心字段写错
支持主键自动生成
内置分页插件
……
2.2 【标准CRUD制作】
问题1:MyBatisPlus内置通用Mapper提供了哪些API?
问题2:Lombok插件的功能?
可以自动生成实体类的GET、SET方法
Lombok,一个Java类库,提供了一组注解,简化POJO实体类开发。
- <dependency>
- <groupId>org.projectlombok</groupId>
- <artifactId>lombok</artifactId>
- <version>1.18.12</version>
- </dependency>
常用注解:
@Data,为当前实体类在编译期设置对应的get/set方法,无参/无参构造方法,toString方法,hashCode方法,equals方法等
代码展示:
- import lombok.*;
- /*
- 1 生成getter和setter方法:@Getter、@Setter
- 生成toString方法:@ToString
- 生成equals和hashcode方法:@EqualsAndHashCode
- 2 统一成以上所有:@Data
- 3 生成空参构造: @NoArgsConstructor
- 生成全参构造: @AllArgsConstructor
- 4 lombok还给我们提供了builder的方式创建对象,好处就是可以链式编程。 @Builder【扩展】
- */
- @Data
- public class User {
- private Long id;
- private String name;
- private String password;
- private Integer age;
- private String tel;
2.3.1 【标准分页功能制作】
问题1:MyBatisPlus实现分页功能步骤?
分页功能接口
MyBatisPlus分页使用
①:设置分页拦截器作为Spring管理的bean
- import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
- import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
- import org.springframework.context.annotation.Bean;
- import org.springframework.context.annotation.Configuration;
-
- @Configuration
- public class MybatisPlusConfig {
-
- @Bean
- public MybatisPlusInterceptor mybatisPlusInterceptor(){
- //1 创建MybatisPlusInterceptor拦截器对象
- MybatisPlusInterceptor mpInterceptor=new MybatisPlusInterceptor();
- //2 添加分页拦截器
- mpInterceptor.addInnerInterceptor(new PaginationInnerInterceptor());
- return mpInterceptor;
- }
- }
②:执行分页查询
- //分页查询
- @Test
- void testSelectPage(){
- //1 创建IPage分页对象,设置分页参数
- IPage<User> page=new Page<>(1,3);
- //2 执行分页查询
- userDao.selectPage(page,null);
- //3 获取分页结果
- 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());
- }
问题2:Mybatis分页底层实现原理?
拦截器
3.1.1 【条件查询的三种格式】
问题1:条件查询的三种格式?
方式一:按条件查询
- //方式一:按条件查询
- QueryWrapper<User> qw=new QueryWrapper<>();
- qw.lt("age", 18);
- List<User> userList = userDao.selectList(qw);
- System.out.println(userList);
方式二:lambda格式按条件查询
- //方式二:lambda格式按条件查询
- QueryWrapper<User> qw = new QueryWrapper<User>();
- qw.lambda().lt(User::getAge, 10);
- List<User> userList = userDao.selectList(qw);
- System.out.println(userList);
方式三:lambda格式按条件查询(推荐)
- //方式三:lambda格式按条件查询
- LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<User>();
- lqw.lt(User::getAge, 10);
- List<User> userList = userDao.selectList(lqw);
- System.out.println(userList);
并且关系(and)
- //并且关系
- LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<User>();
- //并且关系:10到30岁之间
- lqw.lt(User::getAge, 30).gt(User::getAge, 10);
- List<User> userList = userDao.selectList(lqw);
- System.out.println(userList);
或者关系(or)
- //或者关系
- LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<User>();
- //或者关系:小于10岁或者大于30岁
- lqw.lt(User::getAge, 10).or().gt(User::getAge, 30);
- List<User> userList = userDao.selectList(lqw);
- System.out.println(userList);
3.2.1 【条件查询null判定】
问题1:搜索场景,在多条件查询中,有条件的值为空应该怎么解决?
if语句控制条件追加
- Integer minAge=10; //将来有用户传递进来,此处简化成直接定义变量了
- Integer maxAge=null; //将来有用户传递进来,此处简化成直接定义变量了
- LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<User>();
- if(minAge!=null){
- lqw.gt(User::getAge, minAge);
- }
- if(maxAge!=null){
- lqw.lt(User::getAge, maxAge);
- }
- List<User> userList = userDao.selectList(lqw);
- userList.forEach(System.out::println);
问题2:MyBatisPlus是如何对NULL值进行处理的?
条件参数控制
- Integer minAge=10; //将来有用户传递进来,此处简化成直接定义变量了
- Integer maxAge=null; //将来有用户传递进来,此处简化成直接定义变量了
- LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<User>();
- //参数1:如果表达式为true,那么查询才使用该条件
- lqw.gt(minAge!=null,User::getAge, minAge);
- lqw.lt(maxAge!=null,User::getAge, maxAge);
- List<User> userList = userDao.selectList(lqw);
- userList.forEach(System.out::println);
条件参数控制(链式编程)
- Integer minAge=10; //将来有用户传递进来,此处简化成直接定义变量了
- Integer maxAge=null; //将来有用户传递进来,此处简化成直接定义变量了
- LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<User>();
- //参数1:如果表达式为true,那么查询才使用该条件
- lqw.gt(minAge!=null,User::getAge, minAge)
- .lt(maxAge!=null,User::getAge, maxAge);
- List<User> userList = userDao.selectList(lqw);
- userList.forEach(System.out::println);
3.3.1 【查询投影】
问题1:如何指定需要查询字段?
查询结果包含模型类中部分属性
- /*LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<User>();
- lqw.select(User::getId, User::getName, User::getAge);*/
- //或者
- QueryWrapper<User> lqw = new QueryWrapper<User>();
- lqw.select("id", "name", "age", "tel");
-
- List<User> userList = userDao.selectList(lqw);
- System.out.println(userList);
查询结果包含模型类中未定义的属性
- QueryWrapper<User> lqw = new QueryWrapper<User>();
- lqw.select("count(*) as count, tel");
- lqw.groupBy("tel");
-
- List<Map<String, Object>> userList = userDao.selectMaps(lqw);
- System.out.println(userList);
问题2:如果查询投影无法满足需求,应该如何处理?
在Mapper接口中,自定义SQL和查询接口
3.4.1 【查询条件设置】
问题1:多条件查询有哪些组合?
多条件查询有哪些组合?
范围匹配(> 、 = 、between)
模糊匹配(like)
空判定(null)
包含性匹配(in)
分组(group)
排序(order)
……
查询条件案例:
用户登录(eq匹配)
- LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<User>();
- //等同于=
- lqw.eq(User::getName, "Jerry").eq(User::getPassword, "jerry");
- User loginUser = userDao.selectOne(lqw);
- System.out.println(loginUser);
购物设定价格区间、户籍设定年龄区间(le ge匹配 或 between匹配)
- LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<User>();
- //范围查询 lt le gt ge eq between
- lqw.between(User::getAge, 10, 30);
- List<User> userList = userDao.selectList(lqw);
- System.out.println(userList);
查信息,搜索新闻(非全文检索版:like匹配)
- LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<User>();
- //模糊匹配 like
- lqw.likeLeft(User::getName, "J");
- List<User> userList = userDao.selectList(lqw);
- System.out.println(userList);
统计报表(分组查询聚合函数)
- QueryWrapper<User> qw = new QueryWrapper<User>();
- qw.select("gender","count(*) as nums");
- qw.groupBy("gender");
- List<Map<String, Object>> maps = userDao.selectMaps(qw);
- System.out.println(maps);
3.5.1 【映射匹配兼容性】
问题1:如何处理数据表字段和Java实体属性不匹配问题?
表字段与编码属性设计不同步
在模型类属性上方,使用@TableField属性注解,通过value属性,设置当前属性对应的数据库表中的字段关系。
问题2:如何处理数据表字段不存在,Java实体属性存在问题?
编码中添加了数据库中未定义的属性
在模型类属性上方,使用@TableField注解,通过exist属性,设置属性在数据库表字段中是否存在,默认为true。此属性无法与value合并使用。
问题3:如何实现数据表中字段不参与查询,保证数据安全性?
在模型类属性上方,使用@TableField注解,通过==select==属性:设置该属性是否参与查询。此属性与select()映射配置不冲突。
问题4:如何处理 表名和实体名称不一致问题?
在模型类上方,使用@TableName注解,通过==value==属性,设置当前类对应的数据库表名称。
- @Data
- @TableName("tbl_user")
- public class User {
- /*
- id为Long类型,因为数据库中id为bigint类型,
- 并且mybatis有自己的一套id生成方案,生成出来的id必须是Long类型
- */
- private Long id;
- private String name;
- @TableField(value = "pwd",select = false)
- private String password;
- private Integer age;
- private String tel;
- @TableField(exist = false) //表示online字段不参与CRUD操作
- private Boolean online;
- }
4.1.1 【id生成策略】
问题1:一个ID一般来说有哪些要求?
全局唯一:不能出现重复的ID号,既然是唯一标识,这是最基本的要求。
趋势递增:确保生成的ID是对于某个用户或者业务是按一定的数字有序递增的。
高可用性:确保任何时候都能正确的生成ID。
带时间:ID里面包含时间,一眼扫过去就知道哪天的交易。
问题2:id生成策略有哪些?
UUID
Java自带的生成UUID的方式就能生成一串唯一随机32(32个16进制数字)位长度数据,而且够我们用N亿年,全球唯一。
数据库自增ID
中间件
开源算法Snowflake
指定机器 & 同一时刻 & 某一并发序列,是唯一的,据此可生成一个64 bits的唯一ID(long)。
id生成策略控制(@TableId注解)
名称:@TableId
类型:属性注解
位置:模型类中用于表示主键的属性定义上方
作用:设置当前类中主键属性的生成策略
相关属性
type:设置主键属性的生成策略,值参照IdType枚举值
全局策略配置
- mybatis-plus:
- global-config:
- db-config:
- id-type: assign_id
- table-prefix: tbl_
id生成策略全局配置
表名前缀全局配置
问题3:实际工作最常用的id生成策略?
看具体需求,推荐使用snowflake
4.2.2 【多数据操作(删除与查询)】
问题1:mp如何实现批量删除?
- //删除指定多条数据
- List<Long> list = new ArrayList<>();
- list.add(1402551342481838081L);
- list.add(1402553134049501186L);
- list.add(1402553619611430913L);
-
- userDao.deleteBatchIds(list);
问题2:mp如何实现批量删除?
- //查询指定多条数据
- List<Long> list = new ArrayList<>();
- list.add(1L);
- list.add(3L);
- list.add(4L);
- userDao.selectBatchIds(list);
4.3.1 【逻辑删除】
问题1:逻辑删除使用场景?
在实际环境中,如果想删除一条数据,是否会真的从数据库中删除该条数据?
删除操作业务问题:业务数据从数据库中丢弃
问题2:如何实现逻辑删除?
逻辑删除:为数据设置是否可用状态字段,删除时设置状态字段为不可用状态,数据保留在数据库中
逻辑删除案例
①:数据库表中添加逻辑删除标记字段
②:实体类中添加对应字段,并设定当前字段为逻辑删除标记字段
- import com.baomidou.mybatisplus.annotation.*;
-
- import lombok.Data;
-
- @Data
- public class User {
-
- private Long id;
-
- //逻辑删除字段,标记当前记录是否被删除
- @TableLogic
- private Integer deleted;
③:配置逻辑删除字面值
- mybatis-plus:
- global-config:
- db-config:
- table-prefix: tbl_
- # 逻辑删除字段名
- logic-delete-field: deleted
- # 逻辑删除字面值:未删除为0
- logic-not-delete-value: 0
- # 逻辑删除字面值:删除为1
- logic-delete-value: 1
逻辑删除本质:逻辑删除的本质其实是修改操作。如果加了逻辑删除字段,查询数据时也会自动带上逻辑删除字段。
注意:如果不想自动带上逻辑删除字段,需要自己编写SQL。
4.4.1 【乐观锁】
问题1:加锁的场景?乐观锁使用场景?
业务并发现象带来的问题:秒杀
mp提供的乐观锁适用于小型的并发
问题2:mp乐观锁 实现流程和底层原理?
原理:update set xx=yy , version=version+1 where version=num;
mp通过拦截器进行增强
操作流程:
先查询version
修改操作(并发修改只有一个能成功,通过version的值来保证)
乐观锁案例
①:数据库表中添加锁标记字段
②:实体类中添加对应字段,并设定当前字段为逻辑删除标记字段
- import com.baomidou.mybatisplus.annotation.TableField;
- import com.baomidou.mybatisplus.annotation.TableLogic;
- import com.baomidou.mybatisplus.annotation.Version;
- import lombok.Data;
-
- @Data
- public class User {
-
- private Long id;
-
- @Version
- private Integer version;
③:配置乐观锁拦截器实现锁机制对应的动态SQL语句拼装
- import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
- import com.baomidou.mybatisplus.extension.plugins.inner.OptimisticLockerInnerInterceptor;
- import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
- import org.springframework.context.annotation.Bean;
- import org.springframework.context.annotation.Configuration;
-
- @Configuration
- public class MpConfig {
- @Bean
- public MybatisPlusInterceptor mpInterceptor() {
- //1.定义Mp拦截器
- MybatisPlusInterceptor mpInterceptor = new MybatisPlusInterceptor();
-
- //2.添加乐观锁拦截器
- mpInterceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
-
- return mpInterceptor;
- }
④:使用乐观锁机制在修改前必须先获取到对应数据的verion方可正常进行
- @Test
- public void testUpdate() {
- /*User user = new User();
- user.setId(3L);
- user.setName("Jock666");
- user.setVersion(1);
- userDao.updateById(user);*/
-
- //1.先通过要修改的数据id将当前数据查询出来
- //User user = userDao.selectById(3L);
- //2.将要修改的属性逐一设置进去
- //user.setName("Jock888");
- //userDao.updateById(user);
-
- //1.先通过要修改的数据id将当前数据查询出来
- User user = userDao.selectById(3L); //version=3
- User user2 = userDao.selectById(3L); //version=3
- user2.setName("Jock aaa");
- userDao.updateById(user2); //version=>4
- user.setName("Jock bbb");
- userDao.updateById(user); //verion=3?条件还成立吗?
- }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。