1.1.1 创建数据库
这里采用Navicat可视化工具创建数据库,当然,也可以在命令窗口创建,如下:
-
数据库名:mybatis_plus
-
字符集:常用为utf8
-
排序规则:这里选utf8_general_ci
1.1.2 创建User表
这里为了方便演示,就直接创建一个简单的User表
建表语句如下:
DROP TABLE IF EXISTS USER;
CREATE TABLE USER
(
id BIGINT(20) NOT NULL COMMENT ‘主键ID’,
NAME VARCHAR(30) NULL DEFAULT NULL COMMENT ‘姓名’,
age INT(11) NULL DEFAULT NULL COMMENT ‘年龄’,
email VARCHAR(50) NULL DEFAULT NULL COMMENT ‘邮箱’,
PRIMARY KEY (id)
);
插入测试数据:
INSERT INTO user (id,name,age,email) VALUES
(1,‘onestar’,18,‘onestar@136.com’),
(2,‘twostar’,18,‘twostar@136.com’),
(3,‘threestar’,18,‘threestar@136.com’),
(4,‘fourstar’,18,‘fourstar@136.com’),
(5,‘fivestar’,18,‘fivestar@136.com’);
1.2 创建springboot工程
使用idea快捷创建springboot项目,这里就不细说,还有不懂的可以看我之前的文章SpringBoot 框架入门: ,idea快速创建SpringBoot项目那一部分。
注:这里使用的是springboot2.2.1的版本
1.2.1 导入依赖
这里需要将mybatis-plus、MySQL依赖导入,另外,为了简化实体类,不写get、set、tostring方法,添加lombok依赖,用lombok需要下载插件,可以再settings里面的Plugins搜索下载,下载后重启idea
- 导入依赖
com.baomidou
mybatis-plus-boot-starter
3.0.5
mysql
mysql-connector-java
org.projectlombok
lombok
- 下载lombok插件
1.2.2 修改配置文件
springboot配置文件方式有多种,这里选用yml格式的,所以将配置文件后缀改成yml,并添加以下两个配置,如下:
-
数据库配置:driver、url、username、password
-
mybatisplus日置配置:用来在终端显示数据库执行的详细信息
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/mybatis_plus?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=UTC
username: root
password: 806188
mybatis-plus:
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
1.3 代码编写
在com.star包下创建两个包,并创建User实体类和UserMapper接口,目录结构如下:
-
entity包:用来放实体类
-
mapper包:用来放持久层接口
这里还需要让springboot扫描到mapper接口,在MybatisplusdemoApplication类中添加注解@MapperScan(“com.star.mapper”)
@SpringBootApplication
@MapperScan(“com.star.mapper”) //扫描到mapper接口
public class MybatisplusdemoApplication {…}
1.3.1 编写User实体类
package com.star.entity;
import lombok.Data;
/**
-
@Description: User实体类
-
@Date: Created in 11:54 2020/7/28
-
@Author: ONESTAR
-
@QQ群: 530311074
-
@URL: https://onestar.newstar.net.cn/
*/
@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();
}
最后
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数Java工程师,想要提升技能,往往是自己摸索成长,自己不成体系的自学效果低效漫长且无助。
因此收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,不论你是刚入门Android开发的新手,还是希望在技术上不断提升的资深开发者,这些资料都将为你打开新的学习之门!
如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!
n = oldVersion + 1
- newVersion 会回写到 entity 中
- 仅支持 updateById(id) 与 update(entity, wrapper) 方法
- 在 update(entity, wrapper) 方法下, wrapper 不能复用!!!
2.3.2 配置乐观锁插件
在MpConfig配置文件中添加乐观锁配置插件
/**
- 乐观锁插件
*/
@Bean
public OptimisticLockerInterceptor optimisticLockerInterceptor() {
return new OptimisticLockerInterceptor();
}
最后
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数Java工程师,想要提升技能,往往是自己摸索成长,自己不成体系的自学效果低效漫长且无助。
因此收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
[外链图片转存中…(img-Y6gdeWeZ-1714878945857)]
[外链图片转存中…(img-HALhNhsJ-1714878945857)]
[外链图片转存中…(img-nuhs6NGq-1714878945858)]
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,不论你是刚入门Android开发的新手,还是希望在技术上不断提升的资深开发者,这些资料都将为你打开新的学习之门!
如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!