@Data //可以简化实体类
public class User {
@TableId(type = IdType.AUTO)
private Long id;
private String name;
private Integer age;
private String email;
}
分析:
- @Data注解:用于简化实体类,可以不用写get、set等方法
- @TableId(type = IdType.AUTO)注解:这是主键策略注解
* AUTO:表示自动增长策略
* INPUT:表示需要自己设置ID,需要输入
* NONE:表示没有策略,需要输入
* UUID:随机生成唯一的值
* ID\_WORKER:mybatisplus自带策略,生成19位的值,数字类型使用该策略
* ID\_WORKER\_STR:mybatisplus自带策略,生成19位的值,字符串类型使用该策略
1.3.2 编写UserMapper接口
- @Repository注解:可有可无,可以消去依赖注入的报错信息
package com.star.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.star.entity.User;
import org.springframework.stereotype.Repository;
/**
-
@Description: UserMapper接口
-
@Date: Created in 11:57 2020/7/28
-
@Author: ONESTAR
-
@QQ群: 530311074
-
@URL: https://onestar.newstar.net.cn/
*/
@Repository
public interface UserMapper extends BaseMapper {
}
1.3.3 编写测试类(简单增删改查)
编写好以上代码后,框架基本就搭建好了,可以在测试类中进行测试了,在test中添加测试,代码如下:
- 注入mapper
@Autowired
private UserMapper userMapper;
- 简单增删改查
//查询User
@Test
void findUser() {
//查询列表
List user = userMapper.selectList(null);
System.out.println(“user:” + user);
//根据ID查询
User user1 = userMapper.selectById(1L);
System.out.println(“user1:” + user1);
//通过多个ID批量查询
List users = userMapper.selectBatchIds(Arrays.asList(1, 2, 3));
users.forEach(System.out::println);
//简单的条件查询
HashMap<String, Object> map = new HashMap<>();
map.put(“name”, “onestar”);
map.put(“age”, 18);
List users2 = userMapper.selectByMap(map);
users2.forEach(System.out::println);
}
//添加User
@Test
void addUser(){
User user = new User();
user.setName(“sixstar”);
user.setAge(18);
user.setEmail(“sixstar@136.com”);
int insert = userMapper.insert(user);
System.out.println(insert);
}
//修改User
@Test
void updateUser(){
User user = new User();
user.setId(1L);
user.setAge(12);
int result = userMapper.updateById(user);
System.out.println(result);
}
//删除User
@Test
void deleteUser(){
//根据ID删除
int result = userMapper.deleteById(5L);
System.out.println(result);
//批量删除
int result2 = userMapper.deleteBatchIds(Arrays.asList(1,2,3));
System.out.println(result2);
//简单的条件删除
HashMap<String,Object> map = new HashMap<>();
map.put(“name”,“fourstar”);
map.put(“age”,18);
int result3 = userMapper.deleteByMap(map);
System.out.println(result3);
}
分析:
这里基本上都是直接调用mybatisplus封装好了的方法,有一些基本的方法:
- 查询列表:selectList
- 根据ID查询:selectById
- 根据ID批量查询:selectBatchIds
- 条件查询:selectByMap
- 添加:insert
- 根据ID修改:updateById
- 根据ID删除:deleteById
- 根据ID批量删除:deleteBatchIds
- 条件删除:deleteByMap
2. 提升案例
进阶案例主要讲以下几个知识点:
-
分页查询
-
自动填充
-
mybatisplus实现乐观锁
-
逻辑删除
-
性能分析
-
复杂条件查询
2.1 分页查询
Mybatis-Plus是自带了分页查询功能的,直接使用自集成的插件进行分页查询,在使用之前要配置插件,可以专门创建一个配置类来配置插件
2.1.1 配置插件
在com.star包下创建config包,创建MpConfig配置类,添加分页插件
package com.star.config;
import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
-
@Description: 配置类
-
@Date: Created in 10:26 2020/7/29
-
@Author: ONESTAR
-
@QQ群: 530311074
-
@URL: https://onestar.newstar.net.cn/
*/
@Configuration
public class MpConfig {
/**
- 分页插件
*/
@Bean
public PaginationInterceptor paginationInterceptor() {
return new PaginationInterceptor();
}
}
2.1.2 测试分页
//分页查询
@Test
void selectPage(){
//创建page对象(1:当前页;3:每页显示记录数)
Page page = new Page<>(1,3);
//调用分页查询方法,将分页所有数据封装到page对象里面
userMapper.selectPage(page,null);
//通过page对象获取分页数据
System.out.println(page.getCurrent()); //当前页
System.out.println(page.getRecords()); //每页数据list集合
System.out.println(page.getPages()); //总页数
System.out.println(page.getSize()); //每页显示记录数
System.out.println(page.getTotal()); //总记录数
System.out.println(page.hasNext()); //是否有下一页
System.out.println(page.hasPrevious()); //是否有上一页
}
分析:
- 创建page对象:new Page<>(1,3); 参数表示当前页和每页显示记录数
- 调用分页查询方法,将分页所有数据封装到page对象里面:selectPage(page,null);
- 通过调用Mybatisplus插件提供的方法实现分页功能
* page.getCurrent():当前页
* page.getRecords():每页数据list集合
* page.getPages():总页数
* page.getSize():每页显示记录数
* page.getTotal():总记录数
* page.hasNext():是否有下一页
* page.hasPrevious():是否有上一页
2.2 自动填充
在平时开发中,会有些数据需要自动填充,比如创建时间、更新时间等,这就可以使用MybatisPlus的自动填充功能,这里就以创建时间和更新时间为例进行演示
2.2.1 添加字段
User表中添加字段:
-
创建时间:create_time
-
更新时间:update_time
实体类添加属性和注解
@TableField(fill = FieldFill.INSERT)
private Date createTime;
@TableField(fill = FieldFill.INSERT_UPDATE)
private Date updateTime;
2.2.2 实现元对象处理器接口
这里专门创建一个hander包来访处理器接口,在com.star包下创建hander包,创建MyMetaObjectHandler接口
package com.star.hander;
import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
import org.apache.ibatis.reflection.MetaObject;
import org.springframework.stereotype.Component;
import java.util.Date;
/**
-
@Description: 元对象处理器
-
@Date: Created in 14:03 2020/7/29
-
@Author: ONESTAR
-
@QQ群: 530311074
-
@URL: https://onestar.newstar.net.cn/
*/
@Component //交给spring管理
public class MyMetaObjectHandler implements MetaObjectHandler {
//使用MybatisPlus实现添加操作,执行该方法
@Override
public void insertFill(MetaObject metaObject) {
this.setFieldValByName(“createTime”,new Date(),metaObject);
this.setFieldValByName(“updateTime”,new Date(),metaObject);
}
//使用MybatisPlus实现修改操作,执行该方法
@Override
public void updateFill(MetaObject metaObject) {
this.setFieldValByName(“updateTime”,new Date(),metaObject);
}
}
分析:
- @Component:将该类交给spring管理
- metaObject:元数据对象
- setFieldValByName:根据名称来设置值,这里根据创建时间来设置
配置好后可以再测试类中添加User和修改User进行测试
2.3 mybatisplus实现乐观锁
概念
乐观锁和悲观锁
-
悲观锁,顾名思义,就是很悲观,每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,这样别人想拿这个数据就会block直到它拿到锁。悲观锁适用于并发竞争很厉害,写比较多的操作。
-
乐观锁,就是很乐观,每次去拿数据的时候都认为别人不会修改,所以不会上锁,但是在提交更新的时候会判断一下在此期间别人有没有去更新这个数据。乐观锁适用于读多写少的应用场景,这样可以提高吞吐量。
这里只讲乐观锁,为了解决写数据时丢失更新问题而出现的一种解决方法。当多个人同时修改同一条记录,最后提交的把之前的提交数据覆盖,这就是丢失更新,为了防止出现这种情况,就可以采用乐观锁,在提交更新的时候会判断一下在此期间别人有没有去更新这个数据,如12306抢票
MybatisPlus实现原理:通过添加version字段来判断是否对数据进行了修改,修改将version加一,比较新的version和原有的version是不是一样,一样的version才进行更新操作,更新完成后,version就会+1,这时候另外一个拿到数据想要更新的人,在比较version那里就会不同从而更新失败。
2.3.1 添加乐观锁版本号字段
- 添加字段
ALTER TABLE user
ADD COLUMN version
INT
- 实体类添加属性和注解
@Version
@TableField(fill = FieldFill.INSERT_UPDATE) //更新时修改
private Integer version;
添加操作初始化version
//使用MybatisPlus实现添加操作,执行该方法
@Override
public void insertFill(MetaObject metaObject) {
…
this.setFieldValByName(“version”, 1, metaObject);
}
注:
- 支持的数据类型只有 int,Integer,long,Long,Date,Timestamp,LocalDateTime
- 整数类型下 newVersion = oldVersion + 1
- newVersion 会回写到 entity 中
- 仅支持 updateById(id) 与 update(entity, wrapper) 方法
- 在 update(entity, wrapper) 方法下, wrapper 不能复用!!!
2.3.2 配置乐观锁插件
在MpConfig配置文件中添加乐观锁配置插件
/**
- 乐观锁插件
*/
@Bean
public OptimisticLockerInterceptor optimisticLockerInterceptor() {
return new OptimisticLockerInterceptor();
}
2.3.3 测试乐观锁
//乐观锁
@Test
void optimisticLocker(){
//查询
User user = userMapper.selectById(1L);
//修改数据
user.setAge(1);
//修改失败:模拟取出数据后,数据库中version实际数据比取出的值大,即已被其它线程修改并更新了version
//user.setVersion(user.getVersion() - 1);
//执行更新
userMapper.updateById(user);
}
2.4 逻辑删除
删除可以分为两种,一种是物理删除,一种是逻辑删除
-
物理删除:真实删除,将对应数据从数据库中删除,之后查询不到此条删除数据
-
逻辑删除:假删除,将对应数据中代表是否被删除字段状态修改为“被删除状态”,之后在数据库中仍能看到此数据,通过标志位字段来实现
2.4.1 添加字段
- 添加deleted标志位字段
ALTER TABLE user
ADD COLUMN deleted
boolean
- 实体类添加属性和注解
@TableLogic
@TableField(fill = FieldFill.INSERT)
private Integer deleted;
- 添加初始化deleted
//使用MybatisPlus实现添加操作,执行该方法
@Override
public void insertFill(MetaObject metaObject) {
…
this.setFieldValByName(“deleted”, 0, metaObject);
}
2.4.2 配置逻辑删除插件
在MpConfig配置类中添加逻辑删除插件
/**
- 逻辑删除插件
*/
@Bean
public ISqlInjector sqlInjector() {
return new LogicSqlInjector();
}
2.4.3 逻辑删除测试
先添加一条数据,可以看到添加数据的deleted字段默认为0,然后逻辑删除该数据,执行删除后,可以看到数据库中该数据任然在,只是deleted字段由0变成了1,逻辑删除成功
//逻辑删除
@Test
void logicDelete(){
//根据ID删除
int result = userMapper.deleteById(1288666354731237378L);
System.out.println(result);
}
分析:
- 测试后,数据并没有被删除,deleted字段的值由0变成了1,0 和 1 可以在配置文件里面进行配置
- 测试后分析打印的sql语句,是一条update:UPDATE user SET deleted=1 WHERE id=? AND deleted=0
- 被删除数据的deleted 字段的值必须是 0,才能被选取出来执行逻辑删除的操作
- 逻辑删除后查询中包含了where deleted = 0:SELECT id,name,age,email,create_time,update_time,deleted FROM user WHERE deleted=0
2.5 性能分析
性能分析是记录每条SQL语句执行的时间,用来帮助开发者判断某些部分是否还需要优化,有助于发现问题,需要配置插件
2.5.1 配置插件
在MpConfig配置类中添加性能分析配置插件
/**
-
SQL 执行性能分析插件
-
开发环境使用,线上不推荐。 maxTime 指的是 sql 最大执行时长
*/
@Bean
@Profile({“dev”,“test”})// 设置 dev test 环境开启
public PerformanceInterceptor performanceInterceptor() {
PerformanceInterceptor performanceInterceptor = new PerformanceInterceptor();
performanceInterceptor.setMaxTime(100);//ms,超过此处设置的ms则sql不执行
performanceInterceptor.setFormat(true);
return performanceInterceptor;
}
分析:
- setMaxTime(100);:表示超过此处设置的ms则sql不执行,会报错
- @Profile({“dev”,“test”}):当前插件对什么环境起作用,一般有三种环境
* dev环境:表示开发环境
* test环境:表示测试环境
* pro环境:表示产生环境
- 这里表示对开发环境和测试环境性能分析有效,生产环境还去分析性能的话就没必要了,可以针对各环境新建不同的配置文件:
* application-dev.yml
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数Java工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,真正体系化!
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!
如果你觉得这些内容对你有帮助,可以扫码获取!!(备注Java获取)
![img](https://i-blog.csdnimg.cn/blog_migrate/830fd9443ef83488d7c14c6179ff978f.jpeg)
最后
这份《“java高分面试指南”-25分类227页1000+题50w+字解析》同样可分享给有需要的朋友,感兴趣的伙伴们可挑战一下自我,在不看答案解析的情况,测试测试自己的解题水平,这样也能达到事半功倍的效果!(好东西要大家一起看才香)
《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!
下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。**
深知大多数Java工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。[外链图片转存中…(img-LiBLKh8W-1713476409073)]
[外链图片转存中…(img-LwifIv60-1713476409077)]
[外链图片转存中…(img-0fHbsS6w-1713476409078)]
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,真正体系化!
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!
如果你觉得这些内容对你有帮助,可以扫码获取!!(备注Java获取)
![img](https://i-blog.csdnimg.cn/blog_migrate/830fd9443ef83488d7c14c6179ff978f.jpeg)
最后
这份《“java高分面试指南”-25分类227页1000+题50w+字解析》同样可分享给有需要的朋友,感兴趣的伙伴们可挑战一下自我,在不看答案解析的情况,测试测试自己的解题水平,这样也能达到事半功倍的效果!(好东西要大家一起看才香)
[外链图片转存中…(img-aEdKtIQ9-1713476409080)]
[外链图片转存中…(img-JiiYHCuT-1713476409083)]
《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!