本文学习自狂神说,强烈推荐狂神!!!
Mybtais-plus:MyBatis-Plus (baomidou.com)
1.使用Mybatis-plus
创建数据库
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');
创建springboot项目
1、导入对应的依赖
<!-- 数据库驱动-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<!-- Lombok-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<!-- mybatis-plus-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.3.1.tmp</version>
</dependency>
说明:尽量不要同时导入mybatis和mybatis-plus
2、研究依赖如何配置
application.yml
#mysql使用版本 5.7.37 mysql 8以上需要加上时区
spring:
datasource:
username: root
password: 128730
url: jdbc:mysql://localhost:3306/mybatis_plus?useSSL=false&useUnicode=true&characterEncoding=utf-8
driver-class-name: com.mysql.cj.jdbc.Driver
3、代码如何编写
传统方法:pojo-dao(连接mybatis,配置mapper.xml)-service-controller
mybatis-plus:pojo-mapper接口-使用
pojo
package com.example.pojo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
private Long id;
private String name;
private Integer age;
private String email;
}
mapper
package com.example.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.example.pojo.User;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface UserMapper extends BaseMapper<User> {
}
在启动类上面加入注解@MapperScan(mapper文件地址)
@MapperScan("com.example.mapper")
测试
package com.example;
import com.example.mapper.UserMapper;
import com.example.pojo.User;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.util.List;
@SpringBootTest
class MybatisPlusApplicationTests {
@Autowired
private UserMapper userMapper;//继承了BaseMapper 所有的方法都来自BaseMapper
@Test
void contextLoads() {
List<User> userList = userMapper.selectList(null);
userList.forEach(System.out::println);
}
}
2.配置日志
我们所用的sql现在是不可见的,我们希望知道他是怎么执行的,所以我们必须要查看日志
mybatis-plus:
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
3.CRUD 扩展
Insert
@Test
void contextLoads() {
User user = new User();
user.setName("张三");
user.setAge(23);
user.setEmail("1123456777@qq.com");
int insert = userMapper.insert(user);
System.out.println(insert);
System.out.println(user);
}
主键生成策略
分布式系统唯一ID生成方案汇总 - nick hao - 博客园 (cnblogs.com)
雪花算法
snowflake是Twitter开源的分布式ID生成算法,结果是一个long型的ID。其核心思想是:使用41bit作为毫秒数,10bit作为机器的ID(5个bit是数据中心,5个bit的机器ID),12bit作为毫秒内的流水号(意味着每个节点在每毫秒可以产生 4096 个 ID),最后还有一个符号位,永远是0。
自动填充
创建时间 修改时间等操作都是自动化完成的,不需要手动更新
阿里巴巴开发手册:所有的数据库表:gmt_create\gmt_modified几乎所有的表都要配置上!而且需要自动化
方式一 数据库级别(工作中不允许修改数据库 不推荐)
在表中新增字段 create_time 、update_time(默认值CURRENT_TIMESIAMP)
private Date createTime;
private Date updateTime;
@Test
void contextLoads() {
User user = new User();
user.setId(1559512165243789313L);
user.setName("libai");
user.setAge(17);
user.setEmail("测试更新时间");
int update = userMapper.updateById(user);
System.out.println(update);
System.out.println(user);
}
测试
方式二 代码级别
实体类上的属性需要增加注解@TableField
@TableField(fill = FieldFill.INSERT)
private Date createTime;
@TableField(fill = FieldFill.INSERT_UPDATE)
private Date updateTime;
编写处理器
package com.example.handle;
import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.reflection.MetaObject;
import org.springframework.stereotype.Component;
import java.util.Date;
@Slf4j
@Component //将处理器加入到ioc容器中
public class MyMetaObjectHandler implements MetaObjectHandler {
@Override
public void insertFill(MetaObject metaObject) {
log.info("start insert fill.....");
this.setFieldValByName("createTime",new Date(),metaObject);
this.setFieldValByName("updateTime",new Date(),metaObject);
}
@Override
public void updateFill(MetaObject metaObject) {
log.info("start update fill.....");
this.setFieldValByName("updateTime",new Date(),metaObject);
}
}
乐观锁
乐观锁:顾名思义十分乐观,它总是被认为不会出现问题,无论干什么都不去上锁!如果出现了问题,再次更新测试
悲观锁:顾名思义十分悲观,它总是出现问题,无论干什么都会上锁!再去操作
乐观锁
乐观锁实现方式:
- 取出记录时,获取当前 version
- 更新时,带上这个 version
- 执行更新时, set version = newVersion where versio平行线
- 如果version不对,就更新失败
简单来说,就是当要更新一条记录的时候,希望这条记录没有被别人更新
乐观锁: 1、先查询,获得版本号 version=1
--A
update user set name ="shuishui" ,version =version+1
where id =2 and version=1
--B 如果线程抢先完成,这个时候version=2,会导致A修改失败
update user set name ="shuishui" ,version =version+1
where id =2 and version=1
测试乐观锁
1.数据库添加version字段 默认值为1
2.实体类增加相应字段
@Version //乐观锁注解
private Integer version;
3. 注册组件
package com.example.config;
import com.baomidou.mybatisplus.extension.plugins.OptimisticLockerInterceptor;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.transaction.annotation.EnableTransactionManagement;
@Configuration //配置类
@EnableTransactionManagement //自动管理事务
@MapperScan("com.example.mapper") //扫描mapper包
public class MybatisPlusCconfig {
//注册乐观锁插件
@Bean
public OptimisticLockerInterceptor optimisticLockerInterceptor() {
return new OptimisticLockerInterceptor();
}
}
测试
@Test
void contextLoads() {
//线程1
User user = userMapper.selectById(1L);
user.setName("乐观锁111");
user.setEmail("测试乐观锁");
//线程2 插队
User user2 = userMapper.selectById(1L);
user.setName("乐观锁222");
user.setEmail("测试乐观锁");
userMapper.updateById(user2);
userMapper.updateById(user);//如果没有乐观锁 就会覆盖插队线程的值
}
分页查询
分页在网站使用的十分多
1、原始的limit进行分页
2、pageHelper 第三方插件
3、Mybatis-Plus中也内置了分页插件!
Mybatis-Plus分页插件
配置拦截器组件
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
/**
* 新的分页插件,一缓和二缓遵循mybatis的规则
* 需要设置 MybatisConfiguration#useDeprecatedExecutor = false
* 避免缓存出现问题(该属性会在旧插件移除后一同移除)
*/
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.H2));
return interceptor;
}
测试
@Test
void contextLoads() {
Page<User> userPage = new Page<>(1,3);
userMapper.selectPage(userPage,null);
userPage.getRecords().forEach(System.out::println);
}
删除操作
// 根据 entity 条件,删除记录
int delete(@Param(Constants.WRAPPER) Wrapper<T> wrapper);
// 删除(根据ID 批量删除)
int deleteBatchIds(@Param(Constants.COLLECTION) Collection<? extends Serializable> idList);
// 根据 ID 删除
int deleteById(Serializable id);
// 根据 columnMap 条件,删除记录
int deleteByMap(@Param(Constants.COLUMN_MAP) Map<String, Object> columnMap);
逻辑删除
物理删除 :从数据库中直接移出
逻辑删除:在数据库中没有被移出,而是通过一个变量来让他失效,deleted=0变为deleted =1(失效)
eg:管理员可以查看被删除的记录,防止数据的丢失类似于回收站!
说明:
只对自动注入的 sql 起效:
插入: 不作限制
查找: 追加 where 条件过滤掉已删除数据,且使用 wrapper.entity 生成的 where 条件会忽略该字段
更新: 追加 where 条件防止更新到已删除数据,且使用 wrapper.entity 生成的 where 条件会忽略该字段
删除: 转变为 更新
测试:
1.数据库加入delete字段 默认值为0
2.实体类增加对应的属性 添加注解
@TableLogic//逻辑删除
private Integer deleted;
3.配置逻辑删除组件
global-config:
db-config:
logic-delete-field: flag # 全局逻辑删除的实体字段名(since 3.3.0,配置后可以不配置步骤2)
logic-delete-value: 1 # 逻辑已删除值(默认为 1)
logic-not-delete-value: 0 # 逻辑未删除值(默认为 0)
4.测试
删除操作变成了更新操作,将deleted改为了1,而查询的时候也会自动在后面拼接deleted=0;