MybatisPlus - 4、CRUD拓展

文章目录

  • 新增,插入操作
  • 更新操作
  • 自动填充
    • 方式一:数据库级别(工作中不允许操作数据库的时候,这个方法不适用)
    • 方式二:代码级别(使用mybatis plus,这个方法更推荐)
  • 乐观锁
  • 查询操作
    • 批量查询
    • 条件查询map
    • 分页查询
  • 逻辑删除

新增,插入操作

首先看这样一段简单的插入代码:

 @Test
 void insertTest() {
     User user = new User();
     user.setName("zhangsan");
     user.setAge(5);
     user.setEmail("[email protected]");
     userMapper.insert(user);
 }

执行代码后我们查看数据,会看到一条新数据产生,但是请重点关注以下id字段

MybatisPlus - 4、CRUD拓展_第1张图片

这里的id数据库类型是long,id并未自增,mybatisPlus会帮我们自动生产,而这个生产策略是使用了『雪花算法 - SnowFlake https://blog.csdn.net/lq18050010830/article/details/89845790』

等同于pojo中给id加了如下注解

@TableId(type = IdType.ID_WORKER)
private Long id;

接下来我们解读TableId的type类型 - IdType

public enum IdType {
    /*
    主键自增
    1、实体类字段注解:@TableId(type = IdType.AUTO)
    2、数据库字段一定是自增的,如果数据库未设置自增会报错
    */
    AUTO(0),
    // 不维护主键
    NONE(1),
    // 手动输入
    INPUT(2),
    // 全球唯一id
    ID_WORKER(3),
    // 全球唯一id
    UUID(4),
    // WORKER的字符串表示法
    ID_WORKER_STR(5);

    private int key;

    private IdType(int key) {
        this.key = key;
    }

    public int getKey() {
        return this.key;
    }
}

更新操作

代码如下:

 @Test
 void updateTest() {
     User user = new User();
     user.setId(1407693933195702274L);
     user.setName("zhangsan1");
     user.setAge(18);
     userMapper.updateById(user);
 }

这里的 updateById 接受的并非id,而是一个对象,这个方法可以实现动态sql,可以根据id更新其他已经填充的字段,我们看下下面的这张图,注意sql位置

MybatisPlus - 4、CRUD拓展_第2张图片

自动填充

创建时间、修改时间,这些操作我们不希望人工维护,一般都是自动完成的,阿里巴巴java开发手册明确规定,所有的数据库表,gmt_create/gmt_modified(格林尼治时间) 这两个字段必须存在,并且必须自动填充

方式一:数据库级别(工作中不允许操作数据库的时候,这个方法不适用)

在数据库创建两个字段:gmt_create/gmt_modified,时间字段默认值设置为:CURRENT_TIMESTAMP,更新时间字段根据数据库更新操作自动更新

CREATE TABLE `user` (
  `id` bigint(20) NOT NULL COMMENT '主键ID',
  `name` varchar(30) DEFAULT NULL COMMENT '姓名',
  `age` int(11) DEFAULT NULL COMMENT '年龄',
  `email` varchar(50) DEFAULT NULL COMMENT '邮箱',
  `gmt_create` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  `gmt_modified` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

这里注意:数据库中时间字段要求数据类型为:datetime,对应java中的util包Date

private Date gmtCreate;
private Date gmtModified;

到此方式一已经完成,测试观察时间变化

方式二:代码级别(使用mybatis plus,这个方法更推荐)

1、删除数据库对应时间字段的默认值,自动更新操作,保证时间字段在数据库层面什么操作都没有!
2、在对应java实体类的时间属性上增加注解『@TableField』

@TableField(fill = FieldFill.INSERT)
private Date gmtCreate;
@TableField(fill = FieldFill.INSERT_UPDATE)
private Date gmtModified;

3、编写一个处理器(这个处理器官方已经给出了)

@Slf4j
@Component // 处理器已经要加到IOC容器中
public class MyMetaObjectHandler implements MetaObjectHandler {
    @Override
    public void insertFill(MetaObject metaObject) {
        log.info("start insert fill ....");
        // default MetaObjectHandler setFieldValByName(String fieldName, Object fieldVal, MetaObject metaObject)
        this.setFieldValByName("gmtCreate", new Date(), metaObject);
        this.setFieldValByName("gmtModified", new Date(), metaObject);
    }

    @Override
    public void updateFill(MetaObject metaObject) {
        log.info("start update fill ....");
        this.setFieldValByName("gmtModified", new Date(), metaObject);
    }
}

到此方式二已经完成,测试观察时间变化

乐观锁

乐观锁(version):顾名思义总是非常乐观,它总是认为数据不会出现问题,无论干什么都不加锁!每次更新,版本号都会随之变化,如果出现问题,则再次更新值测试 悲观锁:顾名思义总是非常悲观,它总是认为数据会出现问题,无论干什么都加锁!

乐观锁基本操作见下图

MybatisPlus - 4、CRUD拓展_第3张图片

举个例子,sql见下

-- 线程A:查询,获得当前数据的version=1,再更新
update user set name = "xxx", version = version + 1
where id = 1 and version = 1
-- 线程B:查询,获得当前数据的version=1,再更新,这时候线程B抢先完成了更新操作,这时version的值等于2,就会导致线程A更新失败
update user set name = "xxx", version = version + 1
where id = 1 and version = 1

mybatis-plus对乐观锁的支持,我们需要完成以下几步

  • 保证数据库中存在 version 字段,且默认值为1

  • 对应java实体类存在 verison 属性,并且为version字段添加注解『@Version』,这个version注解是mybatis-plus包下的

    @Version
    private Integer version;
    
  • 注册插件

    @MapperScan("com.sun.mapper")
    @EnableTransactionManagement
    @Configuration
    public class MybatisPlusConfig {
        // 注册乐观锁插件
        @Bean
        public OptimisticLockerInterceptor optimisticLockerInterceptor() {
            return new OptimisticLockerInterceptor();
        }
    }
    
  • 更新数据,查看乐观锁支持情况,注意看下sql执行情况

    MybatisPlus - 4、CRUD拓展_第4张图片

    这里在执行update的时候,增加了对version的操作

查询操作

批量查询

List<User> users = userMapper.selectBatchIds(Arrays.asList(1, 2, 3));

MybatisPlus - 4、CRUD拓展_第5张图片

条件查询map

Map<String, Object> map = new HashMap<>();
map.put("age", 18);
List<User> users = userMapper.selectByMap(map);

image-20210706132023715

分页查询

传统分页 limit、pageHelper , mybatis-plus 只需要在MybatisPlusConfig中注册分页插件即可实现分页

// 注册分页插件
@Bean
public PaginationInterceptor paginationInterceptor() {
    return new PaginationInterceptor();
}

执行分页查询代码见下:

// 查询第一页,每页5条
Page<User> page = new Page<>(1, 5);
IPage<User> iPage = userMapper.selectPage(page, null);

得到数据见图:

MybatisPlus - 4、CRUD拓展_第6张图片

『Ipage』对象中的可调用方法也显而易见,分页常用的数据都包含其中

MybatisPlus - 4、CRUD拓展_第7张图片

现在再分析一下sql

MybatisPlus - 4、CRUD拓展_第8张图片

执行2次sql,第一次查询总数,第二次使用limit查询所需数据

逻辑删除

物理删除:从数据库中直接删除 逻辑删除:在数据库中没有直接删除数据,而是通过一个变量让数据失效:deleted=0 标记未删除 deleted=1 标记删除

  • 数据库中增加 deleted 字段,默认值为0
  • java实体类中增加属性 deleted,为该属性添加逻辑删除注解:@TableLogic
@TableLogic
private Integer deleted;
  • 修改配置文件
mybatis-plus.global-config.db-config.logic-delete-value=1 # 逻辑已删除值(默认为 1)
mybatis-plus.global-config.db-config.logic-not-delete-value=0 # 逻辑未删除值(默认为 0)
  • 在MybatisPlusConfig中注册逻辑删除组件
// 注册逻辑删除插件
@Bean
public ISqlInjector sqlInjector() {
    return new LogicSqlInjector();
}
  • 测试删除,观察数据和执行sql

MybatisPlus - 4、CRUD拓展_第9张图片

我们可以看到,逻辑删除生效了,在执行delete操作的时候,mybatis-plus并没有直接对数据库的数据进行抹除操作,而是进行了更新操作,将对应数据的deleted字段更为了1

你可能感兴趣的:(MybatisPlus,java,mybatis)