加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 大数据 > 正文

MyBatisPlus_CRUD扩展

发布时间:2020-12-14 18:04:27 所属栏目:大数据 来源:网络整理
导读:CRUD扩展 目录 CRUD扩展 1. 数据插入 1. 测试插入 2. 主键生成策略 2. 更新 3. 自动填充 1. 数据库级别(工作中不允许修改数据库) 2. 代码级别 4. 乐观锁 1. 给数据库增加version字段 2. 实体类添加对应字段 3. 注册组件 4. 测试乐观锁 1. 成功 2. 失败 5. 查

CRUD扩展

目录
  • CRUD扩展
    • 1. 数据插入
      • 1. 测试插入
      • 2. 主键生成策略
    • 2. 更新
    • 3. 自动填充
      • 1. 数据库级别(工作中不允许修改数据库)
      • 2. 代码级别
    • 4. 乐观锁
      • 1. 给数据库增加version字段
      • 2. 实体类添加对应字段
      • 3. 注册组件
      • 4. 测试乐观锁
        • 1. 成功
        • 2. 失败
    • 5. 查询操作
      • 1. 按照ID查询
      • 2. 条件查询(使用Map)
      • 3. 分页查询
        • 1. 配置拦截器组件即可
        • 2. 直接使用Page对象即可
    • 6. 删除操作
      • 1. 基本的删除操作
      • 2. 逻辑删除
        • 1. 在数据库中加一个deleted字段
        • 2. 实体类中增加一个属性
        • 3. 配置逻辑删除组件
        • 4. 测试删除

1. 数据插入

1. 测试插入

//测试插入
@Test
public void testInsert() {
    User user = new User();
    user.setName("Wang")
            .setAge(3)
            .setEmail("wsk4715@sina.com");

    //帮我们自动生成id
    int result = userMapper.insert(user);

    //受影响的行数
    System.out.println(result);
    //发现,id会自动回填
    System.out.println(user);
}

测试结果

image-20201015135550239

2. 主键生成策略

数据库插入的id默认值为: 全局的唯一id

使用雪花算法,可以保证几乎全球唯一

package com.wang.mybatis_plus.pojo;

import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;

@Data
@AllArgsConstructor
@NoArgsConstructor
@Accessors(chain = true)
public class User {

    @TableId(type = IdType.ID_WORKER)
    private Long id;
    private String name;
    private Integer age;
    private String email;

}

注意

  • @TableId是主键的注解

  • 默认为ID_WORKER 雪花算法

  • image-20201015140532853

  • AUTO

    • 实体类字段上@TableId(type = IdType.AUTO)
    • 数据库字段一定要是自增的,否则报错

2. 更新

//测试更新
@Test
public void testUpdate() {
    User user = new User();
    user.setId(5L)
            .setName("这是修改后的数据")
            .setAge(3)
            .setEmail("wsk4715@sina.com");
    userMapper.updateById(user);
}

注意

  • 虽然叫做updateById,但是参数是一个对象! (根据id更新)

  • 所有的sql都是自动帮你动态配置的

3. 自动填充

创建时间、修改时间!这些个操作一遍都是自动化完成的,我们不希望手动更新!

阿里巴巴开发手册:所有的数据库表: gmt_ create、gmt _modified几乎所有的表都要配置上!而且需要自动化!

1. 数据库级别(工作中不允许修改数据库)

  1. 在表中新增字段 creat_time,update_time

image-20201015142758993

注意要在update_time字段上勾选更新,默认值写CURRENT_TIMESTAMP

  1. 先将实体类同步
package com.wang.mybatis_plus.pojo;

import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;

import java.util.Date;

@Data
@AllArgsConstructor
@NoArgsConstructor
@Accessors(chain = true)
public class User {

    @TableId(type = IdType.ID_WORKER)
    private Long id;
    private String name;
    private Integer age;
    private String email;
    private Date createTime;
    private Date updateTime;

}
  1. 再次更新查看结果

image-20201015143221407

2. 代码级别

  1. 删除默认值和更新

image-20201015143536357

  1. 实体类的字段属性上需要增加注解
package com.wang.mybatis_plus.pojo;

import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;

import java.util.Date;

@Data
@AllArgsConstructor
@NoArgsConstructor
@Accessors(chain = true)
public class User {

    @TableId(type = IdType.ID_WORKER)
    private Long id;
    private String name;
    private Integer age;
    private String email;

    //在插入的时候自动更新
    @TableField(fill = FieldFill.INSERT)
    private Date createTime;
    //在更新的时候自动更新
    @TableField(fill = FieldFill.INSERT_UPDATE)
    private Date updateTime;

}

updateTime用 .INSERT_UPDATE,防止插入创建时间后update为空

  1. 编写处理器来处理这个注解即可
package com.wang.mybatis_plus.handler;

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;

//一定不要忘记把处理器加到IOC容器中
@Component
@Slf4j
public class MyMetaObjectHandler implements MetaObjectHandler {
    //插入时的填充策略
    @Override
    public void insertFill(MetaObject metaObject) {
        log.info("start insert fill....");
        //插入时顺带初始化updateTime,否则为空
        this.setFieldValByName("createTime",new Date(),metaObject);
        this.setFieldValByName("updateTime",metaObject);
    }

    //更新时的填充策略
    @Override
    public void updateFill(MetaObject metaObject) {
        log.info("start update fill....");
        this.setFieldValByName("updateTime",metaObject);
    }
}

注意

  • 实现 MetaObjectHandler 接口
  • 一定不要忘记把处理器加到IOC容器中 @Component

4. 乐观锁

意图:

当要更新一条记录的时候,希望这条记录没有被别人更新

乐观锁实现方式:

  • 取出记录时,获取当前version
  • 更新时,带上这个version
  • 执行更新时, set version = newVersion where version = oldVersion
  • 如果version不对,就更新失败
乐观锁:
1. 先查询,获得版本号 version = 1

-- A
update user set name = "wang",version = version + 1
where id = 2 and version = 1

-- B 线程抢先完成,这个时候 version = 2,会导致 A 修改失败
update user set name = "wang",version = version + 1
where id = 2 and version = 1

1. 给数据库增加version字段

image-20201016101708757

image-20201016101855619

2. 实体类添加对应字段

@Version    //乐观锁version注解
private Integer version;

3. 注册组件

package com.wang.mybatis_plus.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;

//开启管理事务
@EnableTransactionManagement
@Configuration
//扫描我们的Mapper文件夹
@MapperScan("com.wang.mybatis_plus.mapper")
public class MybatisPlusConfig {

    //注册乐观锁插件
    @Bean
    public OptimisticLockerInterceptor optimisticLockerInterceptor() {
        return new OptimisticLockerInterceptor();
    }
}

一定要注册Bean!

4. 测试乐观锁

1. 成功

//测试乐观锁成功
@Test
public void testOptimisticLocker() {
    // 1. 查询用户信息
    User user = userMapper.selectById(1L);
    // 2. 修改用户信息
    user.setName("小明")
            .setEmail("715180879@qq.com");
    // 3. 执行更新操作
    userMapper.updateById(user);

}

2. 失败

//测试乐观锁失败! 多线程下
@Test
public void testOptimisticLocker2() {
    // 线程 1
    User user = userMapper.selectById(1L);
    user.setName("小明")
            .setEmail("715180879@qq.com");
    //模拟另外一个线程执行了插队操作
    User user2 = userMapper.selectById(1L);
    user2.setName("小明2")
            .setEmail("715180879@qq.com");
    userMapper.updateById(user2);

    // 虽然user设置了值但是没有更新,被user2插队更新了同一条数据!
    //如果没有乐观锁,就会覆盖插队线程的值!
    userMapper.updateById(user);
}

image-20201016103356209

可以看出,线程1并没有覆盖另一个线程的更新提交,如果想要多次提交,使用自旋锁

5. 查询操作

1. 按照ID查询

// 测试查询
@Test
public void testSelectById() {
    // 查询单个用户
    User user = userMapper.selectById(1L);
    System.out.println(user);

    // 查询多个用户,要传入一个Collection
    List<User> users = userMapper.selectBatchIds(Arrays.asList(1L,2L,3L));
    for (User user1 : users) {
        System.out.println(user1);
    }
}
  • selectById 查询一个用户
  • selectBatchIds 查询多个用户,参数为 Collection

2. 条件查询(使用Map)

// 按条件查询之一 使用map操作
@Test
public void testSelectByMap() {
    HashMap<String,Object> map = new HashMap<>();
    // 自定义要查询的条件
    map.put("name","小明2");
    List<User> users = userMapper.selectByMap(map);
    for (User user : users) {
        System.out.println(user);
    }
}
  • 在 map 中存放要查询的条件,K-V键值对等效于 where K = V 这句SQL

  • 可以查询多个条件,使用多个K-V键值对即可,MP会帮我们自动拼接SQL

  • K-V键值对中的value一般放一个Object!

3. 分页查询

1. 配置拦截器组件即可

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

2. 直接使用Page对象即可

// 测试分页查询
@Test
public void testPage() {
    //参数 1 : 当前页
    //参数 2 : 页面的大小
    //使用了分页插件后,所有的分页操作也变的简单
    Page<User> userPage = new Page<>(2,5);
    userMapper.selectPage(userPage,null);
    // getRecords 获得当前页所有的记录
    userPage.getRecords().forEach(System.out::println);
}
  • 使用 selectPage 方法只是按照分页查询的结果
  • 查询结果还是用的Page对象
  • Page泛型要传入一个对象

6. 删除操作

1. 基本的删除操作

可以看出,与select中的操作类似,删除单个,删除多个,按照条件删除

// 测试删除
@Test
public void testDeleteById() {
    userMapper.deleteById(1L);
}

2. 逻辑删除

  • 物理删除: 在数据库中直接移除
  • 逻辑删除: 在数据库中没有被移除,而是通过一个变量,来让他失效! deleted = 0 => deleted = 1
    • 管理员可以查看被删除的记录! 防止数据的丢失,类似回收站!

1. 在数据库中加一个deleted字段

image-20201016135753730

默认值为0,没有被删除

2. 实体类中增加一个属性

@TableLogic     //逻辑删除
private Integer deleted;

3. 配置逻辑删除组件

//  逻辑删除组件
    @Bean
    public ISqlInjector sqlInjector() {
        return new LogicSqlInjector();
    }
#配置逻辑删除(删除为0,没有删除为1)
mybatis-plus.global-config.db-config.logic-delete-value=1
mybatis-plus.global-config.db-config.logic-not-delete-value=0

4. 测试删除

// 测试删除
@Test
public void testDeleteById() {
    userMapper.deleteById(2L);
}

image-20201016140619736

记录依旧在数据库,但是值已经变化了

查询的时候会自动过滤被逻辑删除的数据(where deleted = 0)

image-20201016141715832

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读