#配置日志 mybatis-plus: configuration: log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
查看执行sql的日志信息
![](https://upload-images.jianshu.io/upload_images/13465705-974a331de89908f1?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
## 三.Mybatis-plus的CRUD
### 插入操作
// 测试插入 @Test public void testInsert(){ User user = new User(); user.setName(“kwhua_mybatis-plus_insertTest”); user.setAge(15); user.setEmail(“310697723@qq.com”);
int result = userMapper.insert(user); // 帮我们自动生成id
System.out.println(result); // 受影响的行数
System.out.println(user); // 看到id会自动填充。 }
![](https://upload-images.jianshu.io/upload_images/13465705-9b59ecad066c8c01?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
看到id会自动填充。数据库插入的id的默认值为:全局的唯一id
### 主键生成策略
1)主键自增 1、实体类字段上 @TableId(type = IdType.AUTO)
2、数据库id字段设置为自增!![图片](https://upload-images.jianshu.io/upload_images/13465705-de351cfb9eb82523?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
3、再次测试(可以看到id值比上次插入的大1)id的生成策略源码解释
![](https://upload-images.jianshu.io/upload_images/13465705-fa7b9dd4b51c4084?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
public enum IdType { AUTO(0), // 数据库id自增 NONE(1), // 未设置主键 INPUT(2), // 手动输入 ID_WORKER(3), // 默认的方式,全局唯一id UUID(4), // 全局唯一id uuid ID_WORKER_STR(5); //ID_WORKER 字符串表示法 }
以上不再逐一测试。
### 更新操作
@Test public void testUpdate(){ User user = new User(); // 通过条件自动拼接动态sql user.setId(1302223874217295874L); user.setName(“kwhua_mybatis-plus_updateTest”); user.setAge(20); // 注意:updateById 但是参数是一个对象! int i = userMapper.updateById(user); System.out.println(i); }
![](https://upload-images.jianshu.io/upload_images/13465705-675ee0f6877d42e3?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
## 自动填充
创建时间、修改时间!这两个字段操作都是自动化完成的,我们不希望手动更新!阿里巴巴开发手册:所有的数据库表都要配置上gmt_create、gmt_modified!而且需要自动化!
方式一:数据库级别(工作中一般不用)
1、在表中新增字段 gmt_create, gmt_modified
2、把实体类同步
private Date gmtCreate; private Date gmtModified;
3、再次查看
![](https://upload-images.jianshu.io/upload_images/13465705-0498d08b45b3ac04.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
方式二:代码级别 1、删除数据库的默认值、更新操作!
2、实体类字段属性上需要增加注解
// 字段添加填充内容
@TableField(fill = FieldFill.INSERT)
private Date gmt_create;
@TableField(fill = FieldFill.INSERT_UPDATE)
private Date gmt_modified;
3、编写处理器来处理这个注解即可!
@Slf4j @Component // 一定不要忘记把处理器加到IOC容器中! public class MyMetaObjectHandler implements MetaObjectHandler { // 插入时的填充策略 @Override public void insertFill(MetaObject metaObject) { log.info(“start insert fill…”); // setFieldValByName(String fieldName, Object fieldVal, MetaObject metaObject this.setFieldValByName(“gmt_create”,new Date(),metaObject); this.setFieldValByName(“gmt_modified”,new Date(),metaObject); }
// 更新时的填充策略
@Override
public void updateFill(MetaObject metaObject) {
log.info("start update fill.....");
this.setFieldValByName("gmt_modified",new Date(),metaObject);
}
}
4、测试插入和更新,检查时间变化。
## 乐观锁
乐观锁 : 顾名思义,十分乐观,它总是认为不会出现问题,无论干什么不去上锁!如果出现了问题, 再次更新值测试 悲观锁:顾名思义,十分悲观,它总是认为总是出现问题,无论干什么都会上锁!再去操作!
乐观锁实现方式:
取出记录时,获取当前version 更新时,带上这个version 执行更新时, set version = newVersion where version = oldVersion 如果version不对,就更新失败
乐观锁:1、先查询,获得版本号 version = 1
– A update user set name = “kwhua”, version = version + 1 where id = 2 and version = 1 – B 线程抢先完成,这个时候 version = 2,会导致 A 修改失败! update user set name = “kwhua”, version = version + 1 where id = 2 and version = 1
乐观锁测试
1、给数据库中增加version字段!
![](https://upload-images.jianshu.io/upload_images/13465705-8d9414a97bdb896c?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
2、实体类加对应的字段
@Version //乐观锁Version注解
private Integer version;
3、注册组件
// 扫描我们的 mapper 文件夹 @MapperScan(“com.kwhua.mapper”) @EnableTransactionManagement @Configuration // 配置类 public class MyBatisPlusConfig { // 注册乐观锁插件 @Bean public OptimisticLockerInterceptor optimisticLockerInterceptor() { return new OptimisticLockerInterceptor(); } }
4、测试
// 测试乐观锁成功! @Test public void testOptimisticLocker(){ // 1、查询用户信息 User user = userMapper.selectById(1L); // 2、修改用户信息 user.setName(“kwhua”); user.setEmail(“123456@qq.com”); // 3、执行更新操作 userMapper.updateById(user); }
version字段已经由1变成了2
// 测试乐观锁失败!多线程下 @Test public void testOptimisticLocker2(){
// 线程 1
User user = userMapper.selectById(1L);
user.setName("kwhua111");
user.setEmail("123456@qq.com");
// 模拟另外一个线程执行了插队操作
User user2 = userMapper.selectById(1L);
user2.setName("kwhua222");
user2.setEmail("123456@qq.com");
userMapper.updateById(user2);
// 自旋锁来多次尝试提交!
userMapper.updateById(user); // 如果没有乐观锁就会覆盖插队线程的值!
}
![](https://upload-images.jianshu.io/upload_images/13465705-cbc084eb121acc13.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
可以看到线程1执行更新失败
## 查询操作
// 测试查询 @Test public void testSelectById(){ User user = userMapper.selectById(1L); System.out.println(user); }
// 测试批量查询!
@Test
public void testSelectByBatchId(){
List<User> users = userMapper.selectBatchIds(Arrays.asList(1, 2, 3));
users.forEach(System.out::println);
}
// 按条件查询之一使用map操作
@Test
public void testSelectByBatchIds(){
HashMap<String, Object> map = new HashMap<>();
// 自定义要查询
map.put("name","kwhua");
map.put("age",15);
List<User> users = userMapper.selectByMap(map);
users.forEach(System.out::println);
}
1、配置拦截器组件
// 分页插件 @Bean public PaginationInterceptor paginationInterceptor() { return new PaginationInterceptor(); }
2、直接使用Page对象即可!
// 测试分页查询 @Test public void testPage(){ // 参数一:当前页 // 参数二:页面大小 Page page = new Page<>(2,5); userMapper.selectPage(page,null); page.getRecords().forEach(System.out::println); System.out.println(page.getTotal()); }
## 物理删除
// 测试删除 @Test public void testDeleteById(){ userMapper.deleteById(1L); }
// 通过id批量删除
@Test
public void testDeleteBatchId(){
userMapper.deleteBatchIds(Arrays.asList(2L,3L));
}
// 通过map删除
@Test
public void testDeleteMap(){
HashMap<String, Object> map = new HashMap<>();
map.put("name","kwhua");
userMapper.deleteByMap(map);
}
## 逻辑删除
物理删除 :从数据库中直接移除 逻辑删除 :在数据库中没有被移除,而是通过一个变量来让它失效!deleted = 0 => deleted = 1 管理员可以查看被删除的记录!防止数据的丢失,类似于回收站!
1、在数据表中增加一个 deleted 字段
2、实体类中增加属性
@TableLogic //逻辑删除 private Integer deleted;
3、配置
// 逻辑删除组件! @Bean public ISqlInjector sqlInjector() { return new LogicSqlInjector(); }
配置文件配置
global-config: db-config: logic-delete-value: 1 logic-not-delete-value: 0
4、测试 测试删除
![](https://upload-images.jianshu.io/upload_images/13465705-a60e3e41064e6d90?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
字段值也从0修改成了1测试查询
![](https://upload-images.jianshu.io/upload_images/13465705-739a0f83b04d4bda?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
## 性能分析插件
作用:性能分析拦截器,用于输出每条 SQL 语句及其执行时间 MP也提供性能分析插件,如果超过这个时间就停止运行!
1、导入插件
/** * SQL执行效率插件 */ @Bean @Profile({“dev”,“test”})// 设置 dev test 环境开启,保证我们的效率 public PerformanceInterceptor performanceInterceptor() { PerformanceInterceptor performanceInterceptor = new PerformanceInterceptor(); performanceInterceptor.setMaxTime(100); //ms 设置sql执行的最大时间,如果超过了则不执行 performanceInterceptor.setFormat(true); return performanceInterceptor; }
![](https://upload-images.jianshu.io/upload_images/13465705-25854d06abaf2124?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
## 条件构造器(Wrapper)
isNotNull .gt
@Test void contextLoads() { // 查询name不为空的用户,并且邮箱不为空的用户,年龄大于等于12 QueryWrapper wrapper = new QueryWrapper<>(); wrapper .isNotNull(“name”) //不为空 .isNotNull(“email”) .ge(“age”,18);
最后
本人也收藏了一份Java面试核心知识点来应付面试,借着这次机会可以送给我的读者朋友们
目录:
Java面试核心知识点
CodeChina开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频】
一共有30个专题,足够读者朋友们应付面试啦,也节省朋友们去到处搜刮资料自己整理的时间!
Java面试核心知识点
已经有读者朋友靠着这一份Java面试知识点指导拿到不错的offer了,各位读者朋友们快来免费获取吧
…(img-jm2sK5Y9-1630908999550)]
Java面试核心知识点
CodeChina开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频】
一共有30个专题,足够读者朋友们应付面试啦,也节省朋友们去到处搜刮资料自己整理的时间!
[外链图片转存中…(img-rSdk5bvI-1630908999554)]
Java面试核心知识点
已经有读者朋友靠着这一份Java面试知识点指导拿到不错的offer了,各位读者朋友们快来免费获取吧
[外链图片转存中…(img-YfYeBGlD-1630908999556)]
|