mybatis-plus入门

mybatis-plus入门

  1. 创建数据库

    create database mybatis_plus;
    
    use  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,'ame',18,'test1@foxmail.com'),
    (2,'maybe',18,'test1@foxmail.com'),
    (3,'chalice',18,'test1@foxmail.com'),
    (4,'fy',18,'test1@foxmail.com'),
    (5,'xNova',18,'test1@foxmail.com')
    
    
  2. 创建springboot项目

  3. 添加相关依赖(pom.xml)

    <!--mybatis-plus-->
    <dependency>
        <groupId>com.baomidou</groupId>
        <artifactId>mybatis-plus-boot-starter</artifactId>
        <version>3.4.2</version>
    </dependency>
    <!--mysql-->
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
    </dependency>
    <!--lombok-->
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
    </dependency>
    
  4. 设置配置文件(application.properties)

    spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
    spring.datasource.url=jdbc:mysql://localhost:3306/mybatis_plus?serverTimezone=GMT%2B8
    spring.datasource.username=root
    spring.datasource.password=123456
    
  5. 创建实体类(entity.user)

    @Data
    public class User {
        private Long id;
        private String name;
        private Integer age;
        private String email;
    }
    
  6. 创建UserMapper接口(mapper.UserMapper)

    继承BaseMapper<>,通过这个使用mybaits-plus提供的方法

    public interface UserMapper extends BaseMapper<User> {
    
    }
    
  7. 在启动类增加注解扫描mapper包

    @SpringBootApplication
    @MapperScan("com.example.mpdemo01.mapper")
    public class Mpdemo01Application {
    
        public static void main(String[] args) {
            SpringApplication.run(Mpdemo01Application.class, args);
        }
    
    }
    
  8. 编写测试类,启动测试类

    注入userMapper,查询user表数据

    @SpringBootTest
    class Mpdemo01ApplicationTests {
    
        @Autowired
        private UserMapper userMapper;
    
        //查询user表所有数据
        @Test
        void contextLoads() {
            List<User> users = userMapper.selectList(null);
            System.out.println(users);
        }
    
    }
    
  9. 添加日志,启动查询方法

    #日志
    mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
    

    这次可以看到执行的sql语句,执行过程等详细信息

  10. 实现添加一个用户

    //添加一个user
    @Test
    public void adduser(){
        User user = new User();
        user.setName("ori");
        user.setAge(18);
        user.setEmail("test@foxmail.com");
        int insert = userMapper.insert(user);
        System.out.println(insert);
    }
    

    没传主键值会默认生成一个主键,这里会生成一个19位的id,使用的是雪花算法也是mybatis-plus默认的主键策略。

    主键策略 可以使用注解设置策略 @TableId(type= )

    • 自动增长 atuo increment
    • UUID 每次生成一个唯一值
    • redis生成id
    • snowflake算法(雪花算法)
  11. 实现根据id修改user

    @Test
    public void updateUser(){
        User user = new User();
        user.setId(2L);
        user.setAge(100);
        int update = userMapper.updateById(user);
        System.out.println(update);
    }
    
  12. 对比手动和自动填充数据

    在user表中增加两个列:创建时间、修改时间

    alter table user add create_time datetime
    alter table user add update_time datetime
    

    user类增加两个字段

    @Data
    public class User {
        private Long id;
        private String name;
        private Integer age;
        private String email;
        private Date createTime;
        private Date updateTime;
    }
    

    手动实现新增一个user

    //添加一个user
    @Test
    public void adduser(){
        User user = new User();
        user.setName("sumail");
        user.setAge(18);
        user.setEmail("test@foxmail.com");
        user.setCreateTime(new Date());
        user.setUpdateTime(new Date());
        int insert = userMapper.insert(user);
        System.out.println(insert);
    }
    

    自动填充时间实现新增一个user

    1. 在想要自动填充的属性上添加注解(entity.User)

      @TableField(fill = FieldFill.INSERT)
      private Date createTime;
      
      @TableField(fill = FieldFill.INSERT_UPDATE)
      private Date updateTime;
      
    2. 创建类实现接口MetaObjectHandler,重写方法(handler.MyHandler)

      @Component
      public class MyHandler implements MetaObjectHandler {
          @Override
          public void insertFill(MetaObject metaObject) {
              this.setFieldValByName("createTime",new Date(),metaObject);
              this.setFieldValByName("updateTime",new Date(),metaObject);
          }
      
          @Override
          public void updateFill(MetaObject metaObject) {
              this.setFieldValByName("updateTime",new Date(),metaObject);
          }
      }
      
    3. 修改测试类里的添加方法

      //添加一个user
      @Test
      public void adduser(){
          User user = new User();
          user.setName("miracle");
          user.setAge(18);
          user.setEmail("test@foxmail.com");
          // user.setCreateTime(new Date());
          // user.setUpdateTime(new Date());
          int insert = userMapper.insert(user);
          System.out.println(insert);
      }
      

乐观锁解决丢失更新问题

如果不考虑事务隔离性,会产生一些读问题:脏读、不可重复读、幻读

​ 写问题:丢失更新

丢失更新:同时对一个值进行修改,一前一后提交,先提交的数据会被后提交的数据覆盖。

解决方案:悲观锁(串行,每次只能有一个事务对值进行修改,效率低)、乐观锁(并行,添加一个version字段,修改值时对比数据库版本是否一样,如果一样修改成功且数据库版本+1)

乐观锁具体实现

  1. 表添加字段作为版本号,实体类添加属性

    alter table user add version int(11)
    

    这里@TableField是添加数据时给version一个初始值

    @Version
    @TableField(fill = FieldFill.INSERT)
    private Integer version;
    

    添加操作时给version一个默认值1(handler.MyHandler)

    @Component
    public class MyHandler implements MetaObjectHandler {
        @Override
        public void insertFill(MetaObject metaObject) {
            this.setFieldValByName("createTime",new Date(),metaObject);
            this.setFieldValByName("updateTime",new Date(),metaObject);
            this.setFieldValByName("version",1,metaObject);
        }
    
        @Override
        public void updateFill(MetaObject metaObject) {
            this.setFieldValByName("updateTime",new Date(),metaObject);
        }
    }
    
  2. 配置乐观锁 (config.MpConfig)

    可以把启动类中扫描包的注解也放到这个配置类里

    @Configuration
    @MapperScan("com.example.mpdemo01.mapper")
    public class MpConfig {
        //乐观锁
        @Bean
        public OptimisticLockerInnerInterceptor optimisticLockerInnerInterceptor(){
            return new OptimisticLockerInnerInterceptor();
        }
    }
    
  3. 编写测试类

    如果这里是老数据version没有值可以去数据库给一个初始值,不然修改完version还是空

    @Test
    public void testOptimisticLocker(){
        //根据id查询数据
        User user = userMapper.selectById(1);
        //修改
        user.setAge(30);
        userMapper.updateById(user);
    
    }
    

注意:运行碰到报错,就修改配置类或者更换低版本的依赖(修改pom.xml)。这是mybatis-plus版本问题,老版本使用的OptimisticLockerInterceptor 新版本使用的OptimisticLockerInnerInterceptor。

@Configuration
@MapperScan("com.example.mpdemo01.mapper")
public class MpConfig {
    //乐观锁
    @Bean
    public MybatisPlusInterceptor optimisticLockerInnerInterceptor(){
        // return new OptimisticLockerInnerInterceptor();
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
        return interceptor;
    }
}

简单查询:

  1. 通过id查询 selectById(1)

  2. 多个id批量查询 selectBatchIds(Array.asList(1,2,3))

    @Test
    public void select3user(){
        List<User> users = userMapper.selectBatchIds(Arrays.asList(1L, 2L,3L));
        System.out.println(users);
    }
    
  3. 通过map根据条件查询,将条件存入map selectByMap(map)

  4. 分页查询

    1. 配置分页插件

      @Bean
      public PaginationInnerInterceptor paginationInnerInterceptor(){
          return new PaginationInnerInterceptor();
      }
      
    2. 编写分页代码

      new page对象传入两个参数:当前页、每页显示记录数

      调用mp方法,分页所有数据会封装到page对象里

      @Test
          public void testPage(){
              Page<User> page = new Page<>(2,3);
              userMapper.selectPage(page,null);
              System.out.println(page.getCurrent());//当前页
              System.out.println(page.getRecords());//每页数据list集合
              System.out.println(page.getSize());//每页显示记录数
              System.out.println(page.getTotal());//总记录数
              System.out.println(page.getPages());//总页数
              System.out.println(page.hasNext());//是否有下一页
              System.out.println(page.hasPrevious());//是否有上一页
          }
      

      注意:运行发现结果错误应该是版本问题,更改分页插件或者更换低版本的mybatis-plus

      @Bean
      public MybatisPlusInterceptor mybatisPlusInterceptor(){
          MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor();
          mybatisPlusInterceptor.addInnerInterceptor(new PaginationInnerInterceptor());
          return mybatisPlusInterceptor;
      }
      

删除

  1. 删除单条记录

    @Test
    public void testDelete(){
        int result = userMapper.deleteById(1L);
        System.out.println(result);
    }
    
  2. 批量删除

    @Test
    public void tsetDeleteBatchIds(){
        int result = userMapper.deleteBatchIds(Arrays.asList(1, 2));
        System.out.println(result);
    }
    
  3. 逻辑删除(表数据没删除,查询时不显示被逻辑删除的数据)

    1. 表中添加一个字段,实体类添加对应属性并添加逻辑删除注解

      (使用注解自动填充@TableField或者添加字段时加一个default值都可以,这里我使用默认值)

      alter table user add deleted tinyint(1) default 0
      
      @TableLogic
      private Integer deleted;
      
    2. 配置逻辑删除(3.1.1开始不再需要这一步)

      @Bean
      public ISqlInjector sqlInjector(){
          return new LogicSqlInjector();
      }
      
    3. 设置配置文件
      1是删除 0是未删除 这一步默认就是这样可以不写

      mybatis-plus.global-config.db-config.logic-delete-value=1
      mybatis-plus.global-config.db-config.logic-not-delete-value=0
      
    4. 执行删除方法,这次就是逻辑删除,deleted字段从0变为1,查询的时候加一个where deleted=0就不会查到被逻辑删除的数据,mybatis也帮我们封装好了,查询时会自动添加这个条件

      @Test
      public void testDelete(){
          int result = userMapper.deleteById(3);
          System.out.println(result);
      }
      

实现复杂条件查询

一般使用QueryWrapper

@Test
public void testSelectQuery(){
    QueryWrapper<User> wrapper = new QueryWrapper<>();
    //通过QueryWrapper设置条件
    //查询age>=30 ge gt le lt >= > <= <
    wrapper.ge("age",10);
    //查询name=emo    eq等于 ne不等于
    wrapper.eq("name", "emo");
    //范围查询between
    wrapper.between("age",10,30);
    //模糊查询like
    wrapper.like("name","e");
    //降序排列 orderByDesc
    wrapper.orderByDesc("id");
    //last 拼接在语句最后,只能用一次
    wrapper.last("limit 1");
    //指定要查询的列
    wrapper.select("id","name");
    List<User> users = userMapper.selectList(wrapper);
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值