MybatisPlus概述
- 无侵入:只做增强不做改变,引入它不会对现有工程产生影响,如丝般顺滑
- 损耗小:启动即会自动注入基本 CURD,性能基本无损耗,直接面向对象操作
- 强大的 CRUD 操作:内置通用 Mapper、通用 Service,仅仅通过少量配置即可实现单表大部分 CRUD 操作,更有强大的条件构造器,满足各类使用需求
- 支持 Lambda 形式调用:通过 Lambda 表达式,方便的编写各类查询条件,无需再担心字段写错
特点
-
无侵入
-
BaseMapper(条件构造器)
-
内置分页
-
全局拦截插件
快速入门
1. 创建数据库
DROP TABLE IF EXISTS `user`;
CREATE TABLE `user`
(
id BIGINT NOT NULL COMMENT '主键ID',
name VARCHAR(30) NULL DEFAULT NULL COMMENT '姓名',
age INT 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');
2. 初始化springboot项目
<!--连接数据库-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<!--lombok-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<!--mybatisPlus-->
<!-- https://mvnrepository.com/artifact/com.baomidou/mybatis-plus-boot-starter -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.5.2</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
3. 配置数据库连接对象
spring:
datasource:
url: jdbc:mysql://localhost:3306/mybatis_plus?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8
driver-class-name: com.mysql.cj.jdbc.Driver
password: root
username: root
4. 创建实体类
@Data
@AllArgsConstructor
@NoArgsConstructor
@Component
public class User {
private Long id;
private String name;
private int age;
private String email;
}
5. 编写接口
@Repository
@Mapper
public interface UserMapper extends BaseMapper<User> {
}
6. test测试
@SpringBootTest
class MybatisplusApplicationTests {
@Autowired
private UserMapper userMapper;
@Test
void contextLoads() {
List<User> userList = userMapper.selectList(null);
userList.forEach(System.out::println);
}
}
配置日志
我们所有的sql现在不可见,需要到日志功能
mybatis-plus:
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
CRUD拓展
插入操作
插入
@Test
public void testInsert(){
User user = new User();
user.setName("张三");
user.setAge(18);
user.setEmail("123123@qq.com");
int res = userMapper.insert(user);
System.out.println(res);//受影响行数
System.out.println(user);//id会自动回填
}
数据库插入的id的默认值为:全局唯一的id
主键生成策略
默认 ASSIGN_ID
分布式系统唯一id生成策略:分布式系统唯一ID生成方案汇总 - nick hao - 博客园 (cnblogs.com)
雪花算法:
snowflake是Twitter开源的分布式ID生成算法,结果是一个long型的ID。其核心思想是:使用41bit作为毫秒数,10bit作为机器的ID(5个bit是数据中心,5个bit的机器ID),12bit作为毫秒内的流水号(意味着每个节点在每毫秒可以产生 4096 个 ID),最后还有一个符号位,永远是0,可以保证全球唯一。
主键自增
-
实体类字段上增加
@TableId(type = IdType.AUTO)
-
数据库字段是自增的
-
再次测试插入
其余源码解释
AUTO(0),//自增
NONE(1),//未设置主键
INPUT(2),//手动输入
ASSIGN_ID(3),//默认的全局id
ASSIGN_UUID(4);//全局唯一id uuid
更新操作
public void testUpdate(){
User user = new User();
user.setId(6L);
user.setName("李四");
int res = userMapper.updateById(user);//虽然此时是byid,但传入的是一个对象
}
所有的sql都会自动动态给你配置
自动填充策略
创建时间,修改时间,这些操作都是自动完成的,我们不希望手动更新
阿里开发手册:所有的数据库表:gmt_create,gmt_modified几乎所有的表都具备,而且需要自动化。
数据库级别
1. 在表中新建字段create_time,update_time
2. 与实体类同步
代码级别
1. 删除数据库默认值
2.实体类的字段上增加注解
@TableField(fill = FieldFill.INSERT)
private LocalDateTime createTime;
@TableField(fill = FieldFill.INSERT_UPDATE)
private LocalDateTime updateTime;
3. 编写处理器处理注解
@Component
@Slf4j
public class MyMetaObjectHandler implements MetaObjectHandler {
@Override
public void insertFill(MetaObject metaObject) {
log.info("start insert fill ....");
//MetaObjectHandler setFieldValByName(String fieldName, Object fieldVal, MetaObject metaObject)
this.setFieldValByName("createTime", LocalDateTime.now(),metaObject);
this.setFieldValByName("updateTime", LocalDateTime.now(),metaObject);
}
@Override
public void updateFill(MetaObject metaObject) {
log.info("start update fill ....");
this.setFieldValByName("updateTime",LocalDateTime.now(),metaObject);
}
}
乐观锁
乐观锁:无论出现什么问题都不会去上锁,如果出现问题就在测试加锁处理,再次更新值测试
悲观锁:无论干什么都会上锁
-
取出记录时,获取当前 version
-
更新时,带上这个 version
-
执行更新时, set version = newVersion where version = oldVersion
-
如果 version 不对,就更新失败
测试:
1. 数据库字段中增加version字段为1
2. 同步实体类
@Version
private Integer version;
3. 注册乐观锁组件
@EnableTransactionManagement
@Configuration
@MapperScan("com.sfy.mybatisplus.dao")
public class MybatisPlusConfig {
//注册乐观锁插件
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor();
mybatisPlusInterceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
return mybatisPlusInterceptor;
}
}
4. 测试:
成功案例:
@Test
public void TestOptimisticLocker(){
User user = userMapper.selectById(6l);
user.setName("王五");
userMapper.updateById(user);
}
失败案例:
此时可以使用自旋锁进行操作
@Test
public void TestOptimisticLocker2(){
User user = userMapper.selectById(6l);
user.setName("王五1");
//模拟另一个线程插队
User user1 = userMapper.selectById(6l);
user1.setName("王五2");
userMapper.updateById(user1);
userMapper.updateById(user);//如果没有乐观锁就会覆盖插队线程
}
查询操作
1. 单次查询
User user = userMapper.selectById(1l);
2. 批量查询
List<User> users = userMapper.selectBatchIds(Arrays.asList(1l, 2l, 3l));
3. 条件查询
HashMap<String,Object> map = new HashMap<>();
map.put("name","张三");
List<User> users1 = userMapper.selectByMap(map);
users1.forEach(System.out::println);
会自动进行sql拼接
分页查询
使用limit语句
使用pageHelper
MP中内置分页插件
1. 导入插件
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor2() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));//如果配置多个插件,切记分页最后添加
//interceptor.addInnerInterceptor(new PaginationInnerInterceptor()); 如果有多数据源可以不配具体类型 否则都建议配上具体的DbType
return interceptor;
}
2. 直接使用即可
在分页查询之间会进行一次查询总数
删除操作
1. 单条删除
userMapper.deleteById(1l);
2. 批量删除
userMapper.deleteBatchIds(Arrays.asList(1l, 2l, 3l));
3. 条件删除
HashMap<String, Object> map = new HashMap<>();
map.put("name","张三");
userMapper.selectByMap(map);
逻辑删除
物理删除:数据库字段被删除
逻辑删除:数据库字段并没有被删除,而是通过变量使他失效
管理员可以查看被删除得记录,防止数据得丢失,类似于回收站
1. 数据库中添加deleted字段,默认值为0;
2. 同步字段
@TableLogic
private Integer deleted;
3. 配置yml文件
global-config:
db-config:
logic-delete-value: 1
logic-not-delete-value: 0
4. 测试
实际上是进行了一次更新操作
条件构造器Wrapper
可以进行复杂得条件查询
allEq:条件进行拼接
eq:等于
ne:不等于
gt:大于
ge:大于等于
lt:小于
Ie:小于等于
between:范围查询
like:模糊查询
isNull:为空
in:设置条件得范围