MybatisPlus-对Mybatis的增删改查之扩展

insert插入

测试插入SQL,学习主键生成策略

一、编写插入方法的测试代码

@SpringBootTest
class MybatisplusApplicationTests {
   //将UserMapper自动装配到测试类中,因为继承了父类BaseMapper,所有的方法都来自父类
    @Autowired
    private UserMapper userMapper;

    @Test
    void contextLoads() {
        //查询全部用户,这里需要传递一个Wrapper(条件构造器),后面讲解
        List users = userMapper.selectList(null);
        users.forEach(System.out::println);
    }
    
    //测试插入方法
    @Test
    public void testInsert(){
        //插入方法中需要传递一个User对象
        User user = new User();
        
        //通过set方法往对象中传数据,注意这里不给id传数据
        user.setName("张三");
        user.setAge(19);
        user.setEmail("[email protected]");
        
        //调用BaseMapper封装的insert方法,把user对象传进去,返回一个受影响的行数
        int result = userMapper.insert(user);
        System.out.println(result); //result表示受影响的行数
        
        //再次打印刚刚创建的对象
        System.out.println(user);
    }

}

二、运行测试方法,控制台打印结果
发现我们并没有给User对象传递id的参数,系统默认给生成了一个id

MybatisPlus-对Mybatis的增删改查之扩展_第1张图片

三、这里就涉及到了许多的主键生成策略
先拓展一个分布式唯一id生成方案汇总:https://www.cnblogs.com/haoxinyue/p/5208136.html (cnblogs.com)
现在我们系统中默认是用的雪花算法
1、认识什么是雪花算法

2、系统当前默认的主键策略是雪花策略,我们还可以通过注解@TableId设置其他的策略

MybatisPlus-对Mybatis的增删改查之扩展_第2张图片

不同的主键生成策略

通过学习注解@TableId,我们可以了解到可以个性化修改主键的生成策略

MybatisPlus-对Mybatis的增删改查之扩展_第3张图片

点进IdType,发现可以有以下的选择:

MybatisPlus-对Mybatis的增删改查之扩展_第4张图片

一、上一小节讲过了系统当前默认的雪花算法策略,可以回顾一下

二、AUTO表示自增策略,使用方法如下
1、首先在实体类的属性上加上注解@TableId,将Type赋值了AUTO

@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
    
    @TableId(type = IdType.AUTO)
    private Long id;
    private String name;
    private Integer age;
    private String email;
}

2、在数据库中同步操作,将指定的id字段也修改为自增,不然就会报错
注意:修改完表,一定记得点击保存,不然IDEA还是会报错!!!!!!

MybatisPlus-对Mybatis的增删改查之扩展_第5张图片

3、在测试类中测试

@SpringBootTest
class MybatisplusApplicationTests {
   //将UserMapper自动装配到测试类中,因为继承了父类BaseMapper,所有的方法都来自父类
    @Autowired
    private UserMapper userMapper;
    
    //测试插入方法
    @Test
    public void testInsert(){
        //插入方法中需要传递一个User对象
        User user = new User();

        //通过set方法往对象中传数据,注意这里不给id传数据
        user.setName("里弗斯");
        user.setAge(13);
        user.setEmail("[email protected]");

        //调用BaseMapper封装的insert方法,把user对象传进去,返回一个受影响的行数
        int result = userMapper.insert(user);
        System.out.println(result); //result表示受影响的行数

        //再次打印刚刚创建的对象
        System.out.println(user);
    }
}

控制台打印结果:
原本数据库共有6条数据,测试代码中我没有给里弗斯这条数据传id,现在因为我设置了主键自增策略,所以他就自动被赋值为7

MybatisPlus-对Mybatis的增删改查之扩展_第6张图片

三、剩余的策略解释

MybatisPlus-对Mybatis的增删改查之扩展_第7张图片

update更新

通过id更新数据

一、当前数据库的数据

MybatisPlus-对Mybatis的增删改查之扩展_第8张图片


二、编写测试更新的代码

@SpringBootTest
class MybatisplusApplicationTests {
   //将UserMapper自动装配到测试类中,因为继承了父类BaseMapper,所有的方法都来自父类
    @Autowired
    private UserMapper userMapper;
    
    //测试更新
    @Test
    public void testUpdate(){
        //更新方法中需要传递一个User对象
        User user = new User();

        //通过set方法往对象中传数据
        user.setId(1L);
        user.setName("詹姆斯");
        user.setAge(38);
        //注意:这里的通过id更新数据,需要传进一个User对象
        userMapper.updateById(user);
    }
}

三、执行代码,控制台打印结果
MybatisPlus的强大之处是在于它可以根据我们传递进去的参数,自动生成动态SQL

MybatisPlus-对Mybatis的增删改查之扩展_第9张图片

四、观察数据库中数据也成功更新

MybatisPlus-对Mybatis的增删改查之扩展_第10张图片

自动填充

一、为什么要使用自动填充?
每一张数据表中,几乎都会有创建时间、修改时间,但是这些字段在阿里巴巴开发手册中明确规定了,比如gmt_create、gmt_modified几乎所有的表都需要配置上,而且必须实现自动化填充!!!!!!

二、实现自动填充的两种方式
1、数据库级别
(1)在表中新增gmt_create、gmt_modified字段,别忘记修改完点击保存
记得更新时间勾选上更具当前的时间戳更新数据

MybatisPlus-对Mybatis的增删改查之扩展_第11张图片

(2)再次执行更新数据,先在实体类中把字段同步        

 private Date gmt_create;
 private Date gmt_modified; 
    //测试更新
    @Test
    public void testUpdate(){
        //更新方法中需要传递一个User对象
        User user = new User();

        //通过set方法往对象中传数据
        user.setId(1L);
        user.setName("詹姆斯");
        user.setAge(35);
        //注意:这里的通过id更新数据,需要传进一个User对象
        userMapper.updateById(user);
    }

查询数据库更新时间列,的确根据当前更新的时间发生了改变

2、代码级别
(1)删除数据库对创建和更新使劲按字段的默认值或者自动更新操作

MybatisPlus-对Mybatis的增删改查之扩展_第12张图片

(2)在实体类的字段上增加注解

@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {

    @TableId(type = IdType.AUTO)
    private Long id;
    private String name;
    private Integer age;
    private String email;
    //使用注解@TableField,设置该字段是在什么情况下自动填充更新,默认是不更新
    @TableField(fill = FieldFill.INSERT)
    private Date gmt_create;
    @TableField(fill = FieldFill.INSERT_UPDATE)
    private Date gmt_modified;
}

(3)编写处理器来处理这些注解
原理就是我们手动创建一个处理器,并通过@Component注解将该处理器添加到Spring容器中,当我们对某个表中的指定字段做插入或者更新操作的时候,处理器就会对指定的字段填充响应的数据

@Slf4j //可以查看日志信息
@Component //将该类声明为Spring的组件,添加到IOC容器中,才能有效
public class MyMetaObjectHandler implements MetaObjectHandler {
    //插入时的填充策略
    @Override
    public void insertFill(MetaObject metaObject) {
    log.info("insertFull start.....");
    //调用setFieldValByName方法,把指定的字段填充成希望的数据
    this.setFieldValByName("gmt_create",new Date(),metaObject);
    this.setFieldValByName("gmt_modified",new Date(),metaObject);
    }
    //更新时的填充策略
    @Override
    public void updateFill(MetaObject metaObject) {
        log.info("updateFull start.....");
        //更新操作,只更新gmt_modified字段即可
        this.setFieldValByName("gmt_modified",new Date(),metaObject);
    }
}

(4)测试执行插入或者更新操作的代码

@SpringBootTest
class MybatisplusApplicationTests {
   //将UserMapper自动装配到测试类中,因为继承了父类BaseMapper,所有的方法都来自父类
    @Autowired
    private UserMapper userMapper;

    //测试插入方法
    @Test
    public void testInsert(){
        //插入方法中需要传递一个User对象
        User user = new User();

        //通过set方法往对象中传数据,注意这里不给id传数据
        user.setName("恩比德");
        user.setAge(66);
        user.setEmail("[email protected]");

        //调用BaseMapper封装的insert方法,把user对象传进去,返回一个受影响的行数
        int result = userMapper.insert(user);
        System.out.println(result); //result表示受影响的行数

        //再次打印刚刚创建的对象
        System.out.println(user);
    }

    //测试更新
    @Test
    public void testUpdate(){
        //更新方法中需要传递一个User对象
        User user = new User();

        //通过set方法往对象中传数据
        user.setId(2L);
        user.setName("库里");
        user.setAge(28);
        //注意:这里的通过id更新数据,需要传进一个User对象
        userMapper.updateById(user);
    }

}

(5)观察数据库表时间的更新状态,操作成功!

MybatisPlus-对Mybatis的增删改查之扩展_第13张图片

乐观锁插件处理

一、推出这款插件的意图
多线程下,当更新一条记录的时候,希望这条记录没有被别人更新

二、乐观锁的实现方式
1、取出记录时,获取当前的version
2、更新时,带上这个version
3、执行更新时

update XXX set name = "张三",version = newVersion where version = oldVersion

4、如果version不对,那么就更新失败
假设有两条线程,A线程和B线程,两个线程都取出了记录,假设这个原始的version = 1,
如果线程B抢先线程A先更新了数据,version发生了改变,那么线程A再执行更新数据的时候就会发现version不对,更新失败!


三、测试使用乐观锁插件
1、首先在数据库表中增加一个version字段

MybatisPlus-对Mybatis的增删改查之扩展_第14张图片

2、实体类中更新字段,并且在version字段上面增加注解@Version,标记该字段加上了乐观锁

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

3、注册组件
在项目下新建一个config包,下面新建一个mybatisplus的核心配置类,注意这里把扫描mybatis的Mapper接口注解从主启动类中挪到了
mybatisplus的核心配置类下,注册乐观锁的方法,死代码将来直接用

@MapperScan("com.guohui.mapper") //扫描mapper文件夹,编写的mapper接口才能生效
@Configuration //声明该类是一个配置类
public class MybatisPlusConfig {

    //注册乐观锁插件
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor(){
        MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor();
        mybatisPlusInterceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
        return mybatisPlusInterceptor;
    }
}

4、测试乐观锁
(1)单线程下,测试更新数据,肯定能成功将数据更新

    //测试乐观锁一:单线程下数据可以更新成功
    @Test
    public void testOptimisticLocker(){
        //1、通过id查到某个user对象
        User user = userMapper.selectById(1l);
        //2、对这个对象进行更新操作
        user.setName("阿里巴巴");
        user.setAge(99);
        //3、执行一下更新操作,把上面的user对象传进去,此时的对象中的version是1
        userMapper.updateById(user);

    }

数据库中对应数据的version成功更新,默认是执行version+1

(2)多线程下,测试同时更新一行数据,会更新失败

    //测试乐观锁二:多线程下数据会更新失败
    @Test
    public void testOptimisticLocker01() {
        User user1 = userMapper.selectById(2l);
        user1.setName("东七七");
        user1.setAge(43);
        //此时另一个模拟线程过来插队
        User user2 = userMapper.selectById(2l);
        user2.setName("西六六");
        user2.setAge(34);
        userMapper.updateById(user2);
        userMapper.updateById(user1);
    }

(3)查看数据库的表,确实发现只更新了user2中的数据MybatisPlus-对Mybatis的增删改查之扩展_第15张图片

(4)查看并分析控制台的执行日志

MybatisPlus-对Mybatis的增删改查之扩展_第16张图片

MybatisPlus-对Mybatis的增删改查之扩展_第17张图片

select查询

常规查询

    @Test
    public void testSelect(){
        //1.查询单个用户,直接把id传进去即可
        User user = userMapper.selectById(1l);
        System.out.println(user);

        //2.批量查询用户
        List users = userMapper.selectBatchIds(Arrays.asList(1, 2, 3, 4));
        users.forEach(System.out::println);

        //3.通过map来按照条件查询,它可以自动帮我们将map中的数据拼接成动态的SQL
        Map map = new HashMap<>();
        map.put("name","詹姆斯");
        List userList = userMapper.selectByMap(map);
        userList.forEach(System.out::println);
    }

分页查询(插件)

分页在网站中的使用十分频繁,MybatisPlus也内置了分页的插件,所以可以直接拿来使用
一、使用方法
1、在MybatisPlusConfig核心配置文件中注册分页插件

@MapperScan("com.guohui.mapper") //扫描mapper文件夹,编写的mapper接口才能生效
@Configuration //声明该类是一个配置类
public class MybatisPlusConfig {
    
    //注册分页插件
    @Bean
    public PaginationInnerInterceptor paginationInnerInterceptor(){
        return new PaginationInnerInterceptor();
    }
}

2、测试类中,直接使用Page对象即可

    //测试分页查询
    @Test
    public void testPage(){
        Page page = new Page<>(1,5); //两个参数的作用:查询第一页,显示5条数据
        userMapper.selectPage(page, null); //调用selectPage,第二个参数暂时空着
        page.getRecords().forEach(System.out::println);
    }

delete删除

常规删除

    //测试删除
    @Test
    public void testDelete(){
        //通过id删除,DELETE FROM user WHERE id = ?
        userMapper.deleteById(8l);
        
        //批量删除,DELETE FROM user WHERE id IN(?,?,?)
        userMapper.deleteBatchIds(Arrays.asList(4,5,6));
        
        //通过map自定义删除,动态拼接SQL,DELETE FROM user WHERE id = ?
        Map map = new HashMap<>();
        map.put("id",7);
        userMapper.deleteByMap(map);
    }

逻辑删除(插件)

一、首先先了解两个概念
1、物理删除
从数据库中直接移除
2、逻辑删除
在数据库中没有被移除,而是通过一个变量来让他失效!比如说deleted = 0变为deleted = 1

二、测试逻辑删除
1、在数据库表中增加一个deleted字段,默认值为0

MybatisPlus-对Mybatis的增删改查之扩展_第18张图片

2、实体类pojo中更新字段,并且增加逻辑删除的注解

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

3、在application.properties中配置逻辑删除

#配置逻辑删除,删除了deleted字段为1,没有删除的为0
mybatis-plus.global-config.db-config.logic-delete-value=1
mybatis-plus.global-config.db-config.logic-not-delete-value=0

4、测试删除
(1)数据库原数据

(2)执行删除操作

    //测试逻辑删除
    @Test
    public void testDelete(){
        //通过id删除,DELETE FROM user WHERE id = ?
        userMapper.deleteById(1l);
    }

注意:我们虽然执行的是删除的方法,但是它实际执行的是更新的SQL        

(3)查看数据库更新数据
发现我们这条数据依旧存在,但是deleted的值发生了改变

更加有意思的是,我们再对第一条数据执行查询操作的时候,他会自动帮助我们把deleted = 0拼接上去,所以这条数据就无法查询到。换句话说,逻辑删除的插件会让系统自动过滤掉被逻辑删除的数据

至此,关于MybatisPlus对Mybatis的CRUD扩展的介绍就结束了,你已经掌握了对常规的增删改查的功能,后续会继续更新,欢迎交流和指正!

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