zoukankan      html  css  js  c++  java
  • MyBatisPlus_CRUD扩展

    CRUD扩展

    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", new Date(), metaObject);
        }
    
        //更新时的填充策略
        @Override
        public void updateFill(MetaObject metaObject) {
            log.info("start update fill....");
            this.setFieldValByName("updateTime", new Date(), 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

  • 相关阅读:
    谈谈IE条件注释
    0916 编程实验一 词法分析程序
    C语言文法的理解
    复利究极算法
    0106递归下降语意分析
    0309 复利计算
    关于语法树和文法的评价
    10.22 词法分析程序实验心得
    0909 编译原理
    0302 关于就业方面的一些感想
  • 原文地址:https://www.cnblogs.com/wang-sky/p/13838629.html
Copyright © 2011-2022 走看看