快速开始
本篇文章是在哔哩哔哩秦疆老师的mybatisplus教程下做的笔记,并且插入了一些自己的理解。
1. 新建springboot项目导入pom依赖
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.0.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>org.example</groupId>
<artifactId>mybatisplus01</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<!--mybatis-plus 导入了这个就不能导入mybatis了 3.0.5-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.0.5</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.19</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.16.10</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<!--处理jar包冲突-->
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
<!--thymeleaf-->
<dependency>
<groupId>org.thymeleaf</groupId>
<artifactId>thymeleaf-spring5</artifactId>
</dependency>
<dependency>
<groupId>org.thymeleaf.extras</groupId>
<artifactId>thymeleaf-extras-java8time</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>ava
在这里插入代码片
- 改配置 application.properties,yml文件也行
spring.datasource.username=root
spring.datasource.password=admin
spring.datasource.url=jdbc:mysql:///mybatisplus?serverTimezone=UTC&characterEncoding=utf-8
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
#默认日志,其它的要导依赖。你也可以用别的日志
mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
server.port=8081
- 在类路径下新建pojo包存放数据,再建一个User类
@Data //我这里是安装了lombok插件的,没安装自己手动生成getter,setter,tostring还有构造。
@AllArgsConstructor
@NoArgsConstructor
public class User {
private Long id;
private String name;
private Integer age;
private String email;
}
- 在类路径下新建mapper包,再建一个UserMapper接口
//在对应的mapper上继承BaseMapper<T>接口
@Repository
public interface UserMapper extends BaseMapper<User> {
//BaseMapper点进去,你会发现它已经帮你做好了sql操作CRUD相应的方法。
}
- 建立数据库
create database mybatisplus;
use mybatisplus;
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, 'Jone', 18, 'test1@baomidou.com'),
(2, 'Jack', 20, 'test2@baomidou.com'),
(3, 'Tom', 28, 'test3@baomidou.com'),
(4, 'Sandy', 21, 'test4@baomidou.com'),
(5, 'Billie', 24, 'test5@baomidou.com');
- 测试
//注意注意注意注意注意注意注意注意注意注意注意注意
//测试前给主启动类加上@MapperScan("com.example.mybatisplus.mapper")开启包扫描
@SpringBootTest
public class MybatisPlus01ApplicationTest {
@Autowired
UserMapper userMapper;
//查询测试
@Test
void contextLoads(){
//这里条件为null查所有
List<User> users = userMapper.selectList(null);
users.forEach(System.out::println);
}
//插入测试
@Test
void testInsert(){
User user =new User();
user.setName("老王");
user.setAge(22);
user.setEmail("1231213@qq.com");
//自动生成id
int result = userMapper.insert(user);
System.out.println(result);
System.out.println(user);
}
//测试更新
@Test
void testUpdate(){
User user =new User();
user.setId(6L);//这个如果后面自动生成了主键要注释掉
user.setName("老李");
user.setAge(19);
int i = userMapper.updateById(user);
System.out.println(i);
}
}
分布式系统唯一id生成方案
参考博客:https://www.cnblogs.com/haoxinyue/p/5208136.html](https://www.cnblogs.com/haoxinyue/p/5208136.html)
雪花算法:
snowflake是Twitter开源的分布式ID生成算法,结果是一个long型的ID。其核心思想是:使用41bit作为毫秒数,10bit作为机器的ID(5个bit是数据中心,5个bit的机器ID),12bit作为毫秒内的流水号(意味着每个节点在每毫秒可以产生 4096 个 ID),最后还有一个符号位,永远是0。具体实现的代码可以参看https://github.com/twitter/snowflake
//注意在集群环境下用数据库的主键自增并不好,会出现单点故障。详情请参考上面博客
//user类 对应数据库中的主键自动生成
@TableId(type = IdType.ID_WORKER)
private Long id;
自动填充处理
方案一、注意数据库最好不要轻易改动
1. 在数据库里user表新增两个日期类型字段create_time,update_time设置默认值
2. 在user类中加上添加好的字段,over
方案二、
1. 记得先去掉刚设置的默认值,在user类加上的字段上加上注解
// 字段添加填充内容
@TableField(fill= FieldFill.INSERT)
private Date createTime; //这里有个坑你这里这么写,你数据库的字段必须是create_time
@TableField(fill= FieldFill.INSERT_UPDATE)
private Date updateTime;
2. 点进 FieldFill它是字段填充的意思
@TableField("字段名")当数据库字段与类中不一样时也可以这样使用
public enum FieldFill {
DEFAULT,
INSERT, //当执行insert语句时执行
UPDATE, //当执行UPDATE语句时执行
INSERT_UPDATE;//当执行insert和UPDATE语句时执行
private FieldFill() {
}
}
- 测试
乐观锁
乐观锁 : 故名思意十分乐观,它总是认为不会出现问题,无论干什么不去上锁!如果出现了
问题,再次更新值测试
悲观锁:故名思意十分悲观,它总是认为总是出现问题,无论干什么
都会上锁!再去操作!
乐观锁实现方式:
取出记录时,获取当前 version
更新时,带上这个version
执行更新时,set version = newVersion where version = oldVersion
如果version不对,就更新失败
**乐观锁:先查询,获得版本号 version = 1
-- A
update user set name = "老李1111", version = version + 1
where id = 2 and version = 1
-- B
如果查询版本号也是1但此线程抢先完成,这个时候 version = 2,会导致 A 修改失败!
update user set name = "老李2222", version = version + 1
where id = 2 and version = 1**
1.
添加字段version int ,加上default约束
添加默认约束语法:alter table user change column version version int default 1;
删除默认约束语法:把default后面的值改成null就行
2.
在user类里把字段补上
@Version //乐观锁
private Integer version;
3.注册乐观锁插件
类路径下新建config包,再新建MyBatisPlusConfig类,这个时候主启动类的包扫描注解就
可以放到这里了
@MapperScan("com.example.mybatisplus.mapper")
@Configuration
public class MyBatisPlusConfig {
// 注册乐观锁插件
@Bean
public OptimisticLockerInterceptor optimisticLockerInterceptor() {
return new OptimisticLockerInterceptor();
}
}
- 测试
在测试类添加方法
// 测试乐观锁成功!
@Test
public void testOptimisticLocker(){
// 1、查询用户信息
User user=userMapper.selectById(1L);
// 2、修改用户信息
user.setName("老李111");
user.setEmail("123123123@qq.com");
// 3、执行更新操作,执行完这条语句你会发现version+1变成了2
userMapper.updateById(user);
}
// 测试乐观锁失败!多线程下!
@Test
public void testOptimisticLocker2(){
// 1、查询用户信息
User user=userMapper.selectById(1L);
// 2、修改用户信息
user.setName("老李1111");
user.setEmail("123123123@qq.com");
// 3、执行更新操作
// 模拟另外一个线程执行了插队操作
User user2=userMapper.selectById(1L);
user2.setName("老李2222");
user2.setEmail("123123123@qq.com");
userMapper.updateById(user2);//此时version=3
// 可以尝试自旋锁来多次尝试提交!
//执行到这里你会发现version本来是2但跟新两次应该是+了两次1可结果version却是3说明有一个没有执行。
//再看name=“老李222”userMapper.updateById(user2);明明先执行却没有被 userMapper.updateById(user);覆盖
//说明这里如果没有乐观锁就会覆盖插队线程的值!
//此时version=3+1不等于3,所以被锁了。
userMapper.updateById(user);
}
查询
常规查询
// 测试查询
//这里提示看下源码,其实非常好懂。
@Test
public void testSelectById() {
//查id=1的用户,看下日志里面有拼接好的sql
User user = userMapper.selectById(1L);
System.out.println(user);
}
// 测试批量查询!
@Test
public void testSelectByBatchId() {
//查id=1 ro 2 ro 3
//注意Arrays工具类是import java.util.Arrays;下的
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<>();
// 自定义查询 select * from where name = '老李222' and age = 19
map.put("name", "老李222");
map.put("age", 19);
List<User> users = userMapper.selectByMap(map);
users.forEach(System.out::println);
}
分页查询(很重要)
1. 配置拦截器组件(在MyBatisPlusConfig类里加如下代码)
// 分页插件(官网里有详细描述)
@Bean
public PaginationInterceptor paginationInterceptor() {
return new PaginationInterceptor();
}
2. 测试类里使用内置page对象测试
// 测试分页查询
@Test
public void testPage() {
// 参数一:当前页 参数二:页面大小
// 使用了分页插件之后,所有的分页操作也变得简单的!
Page<User> page = new Page<>(1, 3);
userMapper.selectPage(page, null);
//获取并输出所有数据
page.getRecords().forEach(System.out::println);
//总页数Total: 3
System.out.println(page.getTotal());
}
删除
常规删除
// 测试删除
@Test
public void testDeleteById() {
userMapper.deleteById(1240620674645544965L);
}
// 通过id批量删除
@Test
public void testDeleteBatchId() {
userMapper.deleteBatchIds(Arrays.asList(1L, 2L));
}
// 通过map自定义删除
@Test
public void testDeleteMap() {
HashMap<String, Object> map = new HashMap<>();
map.put("name", "老李222");
userMapper.deleteByMap(map);
}
逻辑删除
物理删除:从数据库中直接移除
逻辑删除:在数据库中没有被移除,而是通过一个变量来让他失效! 假设这个变量为 deleted。
我们通过一个update语句让原本deleted=0改为deleted=1让原本查询语句依赖这个
deleted=0查询就查不到了。这就是所谓的逻辑删除!
例:管理员可以查看被删除的记录!防止数据的丢失,类似于回收站!
1. 在数据表中增加一个 deleted 字段设为int,给个默认值0
2. user类里加上字段
@TableLogic //逻辑删除:实际上只是把这个delete字段值改了一下让原本的查询语句查不出来
private Integer deleted;
3. 配置 在MyBatisPlusConfig类加上如下代码
// 逻辑删除组件!
@Bean
public ISqlInjector sqlInjector() {
return new LogicSqlInjector();
}
4. 然后在application.properties里添加配置
#配置逻辑删除
#删除后的delete值设为1
mybatis-plus.global-config.db-config.logic-delete-value=1
#没删除前的delete值设为0
mybatis-plus.global-config.db-config.logic-not-delete-value=0
5. 测试一下删除操作
好了入门篇就到这里,进阶篇等我至少做完一个相关项目再说。