mybatis_plus

发布时间 2023-08-04 11:00:51作者: 似初吖

Mybatis-plus

1. 快速入门

1.建数据库
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, 'Jone', 18, 'test1@baomidou.com'),
(2, 'Jack', 20, 'test2@baomidou.com'),
(3, 'Tom', 28, 'test3@baomidou.com'),
(4, 'Sandy', 21, 'test4@baomidou.com'),
(5, 'Billie', 24, 'test5@baomidou.com');
2. 导入依赖
<dependencies>

    <!-- 数据库 -->
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
    </dependency>
    <!-- lombok -->
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
    </dependency>
    <!-- mybatis-plus -->
    <dependency>
        <groupId>com.baomidou</groupId>
        <artifactId>mybatis-plus-boot-starter</artifactId>
        <version>3.5.3</version>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>
</dependencies>
3. 连接数据库
spring.datasource.username=root
spring.datasource.password=zy20000229ymy.
spring.datasource.url=jdbc:mysql://localhost:3306/mybatis_plus?useSSL=false&useUnicode=true&characterEncoding=utf-8
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
4. 传统的 pojo-dao(连接mybatis,配置mapper.xml文件)-service-controller
4. 使用了Mybatis-plus之后
  • pojo

    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    public class User {
        private Long id;
        private String name;
        private Integer age;
        private String email;
    }
    
  • mapper接口

    @Repository //持久层
    public interface UserMapper extends BaseMapper<User> {
        //所有的CRUD操作都已编写完成
        //不需要像之前一样配置很多东西
    }
    
  • 注意点:我们需要在主动类上去扫描mapper包下的所有接口

    //扫描 mapper 文件夹
    @MapperScan("com.zhang.mapper")
    @SpringBootApplication
    public class MybatisPlusApplication {
        public static void main(String[] args) {
            SpringApplication.run(MybatisPlusApplication.class, args);
        }
    }
    
  • 使用

    @SpringBootTest
    class MybatisPlusApplicationTests {
        @Autowired
        private UserMapper userMapper;
        @Test
        void contextLoads() {
            //查询全部用户, 参数是一个Wrapper,条件是参数构造器
            List<User> userList = userMapper.selectList(null);
            userList.forEach(System.out::println);
        }
    }
    

2. 配置日志

我们的sql现在是不可见的,我们希望知道它是怎么执行的,必须看日志

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

3. CRUD扩展

1. Insert
@Test
public void testInsert(){
    User user = new User();
    user.setName("张三");
    user.setAge(20);
    user.setEmail("zy12311321321@163.com");
    int insert = userMapper.insert(user); //帮我们自动生成id   用了雪花算法
    System.out.println(insert);  // 受影响的行数
    System.out.println(user);   // id会自动回填  
}

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

主键生成策略

默认ID_WORKER 全局唯一id

雪花算法

主键自增

我们要实现主键自增:

  1. 实体类字段上 @TableId(type = IdType.AUTO)
  2. 数据库字段一定要是自增
2. update
@Test
public void testUpdate(){
    //通过条件自动拼接动态SQL
    User user = new User();
    user.setId(3L);
    user.setName("真的很好呀");
    
    //注意:updateById 参数是一个对象!!!
    int i = userMapper.updateById(user);
    System.out.println(i);
}

自动填充

创建时间,修改时间!!!

方式一:数据库级别

  1. 在表中新增字段create_time,update_time
  2. 再次测试插入方法,我们需要先把实体类同步
  3. 更新查看结果就出来了,时间会自己添上的。

方式二:代码级别

  1. pojo 字段上加注解

    //字段添加填充内容
    @TableField(fill = FieldFill.INSERT)
    private Date createTime;
    @TableField(fill = FieldFill.INSERT_UPDATE)
    private Date updateTime;
    
  2. 编写处理器来处理这个注解

    @Slf4j
    @Component  //一定不要忘记把处理器加到IOC容器中
    public class MyMetaObjectHandler implements MetaObjectHandler {
    
        //插入时的填充策略
        @Override
        public void insertFill(MetaObject metaObject) {
            log.info("Start insert fill....");
    
            this.setFieldValByName("createTime",new Date(),metaObject);
            this.setFieldValByName("updateTime",new Date(),metaObject);
        }
    
        //更新时填充策略
        @Override
        public void updateFill(MetaObject metaObject) {
            log.info("Start insert fill....");
            this.setFieldValByName("updateTime",new Date(),metaObject);
        }
    }
    
  3. 测试插入

  4. 测试更新,观察时间即可

乐观锁

测试理解

乐观锁:总是认为不会出现问题,无论干什么都不去上锁,如果出现问题,再次更新值测试

悲观锁:总是认为会出问题,无论干什么都会去上锁,再去操作。

乐观锁的实现方式:

  • 取出记录时,获取当前 version
  • 更新时,带上这个 version
  • 执行更新时, set version = newVersion where version = oldVersion
  • 如果 version 不对,就更新失败。

测试一下MP的乐观锁插件

  1. 给数据库增加version字段

  2. 我们实体类加对应字段

    @Version
    private Integer version;
    
  3. 注册组件

    //扫描 mapper 文件夹
    @MapperScan("com.zhang.mapper")
    @EnableTransactionManagement
    @Configuration
    public class MyBatisPlusConfig {
        //注册乐观锁
        @Bean
        public MybatisPlusInterceptor mybatisPlusInterceptor() {
            MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
            interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
            return interceptor;
        }
    }
    
  4. 测试

    //测试乐观锁成功(单线程)
    @Test
    public void testOptimisticLocker(){
        //1. 查询用户信息
        User user = userMapper.selectById(1L);
        //2. 修改用户信息
        user.setName("李四");
        user.setAge(11);
        //3. 执行更新操作
        userMapper.updateById(user);
    }
    
3. 查询操作
//测试批量查询
@Test
public void testSelectByBatchId(){
    List<User> userList = userMapper.selectBatchIds(Arrays.asList(1, 2, 3));
    userList.forEach(System.out::println);
}
// 按条件查询之一使用map操作(同一条数据的条件)
@Test
public void testSelectByBachIds(){
    HashMap<String, Object> map = new HashMap<>();
    //自定义要查询的条件
    map.put("name","张三");
    map.put("age",22);
    List<User> users = userMapper.selectByMap(map);
    users.forEach(System.out::println);
}
分页查询
  1. 分页插件

    //分页插件
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor2(){
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.H2));
        return interceptor;
    }
    
  2. 测试

    //分页
    @Test
    public void testPage(){
        //参数一:当前页  参数二:页面大小
        Page<User> page = new Page<>(1,2);
        userMapper.selectPage(page,null);
        page.getRecords().forEach(System.out::println);
        System.out.println(page.getTotal());
    }
    
  3. 数据库操作

    日志:
    Preparing: 
    SELECT id,name,age,email,version,deleted,create_time,update_time 
    FROM user 
    WHERE deleted=0 
    LIMIT ?
    Parameters: 2(Long)
    
4. 删除操作

基本的删除操作

//测试删除
@Test
public void testDeleteById(){
    userMapper.deleteById(11);
}
//通过id批量删除
@Test
public void testDeleteBatchId(){
    userMapper.deleteBatchIds(Arrays.asList(8,9));
}
//通过map删除
@Test
public void testDeleteMap(){
    Map<String, Object> map = new HashMap<>();
    map.put("name","张三");
    userMapper.deleteByMap(map);
}

逻辑删除

物理删除:从数据库中直接移除

逻辑删除:数据库中没有移除,而是通过一个变量让它失效。 deleted=0 ==>deleted=1

管理员可以查看被删除的记录,防止数据丢失,类似于回收站

测试:

  1. 在数据库中添加deleted字段

  2. 实体类中增加属性

    @TableLogic  //逻辑删除
    private Integer deleted;
    
  3. 逻辑删除配置(application.yml/properties)

    mybatis-plus:
    global-config:
    db-config:
    logic-delete-field: flag # 全局逻辑删除的实体字段名(since 3.3.0,配置后可以忽略不配置步骤2)
    logic-delete-value: 1 # 逻辑已删除值(默认为 1)
    logic-not-delete-value: 0 # 逻辑未删除值(默认为 0)
    
  4. 测试删除数据

    @Test
    public void testDeleteById(){
        userMapper.deleteById(1);
    }
    

    走的逻辑

    UPDATE user SET deleted=1 WHERE id=? AND deleted=0
    
  5. 通过查询语句查询 发现查不出来

4. 条件构造器Wrapper

1. 查询name,邮箱不为空的用户,年龄大于等于21
@Test
public void selectWp(){
    //查询name,邮箱不为空的用户,年龄大于等于21
    QueryWrapper<User> wrapper = new QueryWrapper<>();
    wrapper.isNotNull("name")
        .isNotNull("email")
        .ge("age",21);
    userMapper.selectList(wrapper).forEach(System.out::println);
}
日志:
Preparing:
SELECT id,name,age,email,version,deleted,create_time,update_time 
FROM user 
WHERE deleted=0 AND (name IS NOT NULL AND email IS NOT NULL AND age >= ?)
Parameters: 21(Integer)
2. 查询名字Sandy
@Test
public void test2(){
    QueryWrapper<User> wrapper = new QueryWrapper<>();
    wrapper.eq("name","Sandy");
    User user = userMapper.selectOne(wrapper); //查询一个数据,出现多个结果使用List,或者Map
    System.out.println(user);
}
日志:
Preparing: 
SELECT id,name,age,email,version,deleted,create_time,update_time 
FROM user 
WHERE deleted=0 AND (name = ?)
Parameters: Sandy(String)
3. 查询年龄在20~30之间的用户数量
@Test
public void test3(){
    QueryWrapper<User> wrapper = new QueryWrapper<>();
    wrapper.between("age",20,30);
    Long count = userMapper.selectCount(wrapper);
    System.out.println(count);
}
日志:
Preparing: 
SELECT COUNT( * ) AS total 
FROM user 
WHERE deleted=0 AND (age BETWEEN ? AND ?)
Parameters: 20(Integer), 30(Integer)
4. 模糊查询
@Test
public void test4(){
    QueryWrapper<User> wrapper = new QueryWrapper<>();
    wrapper.notLike("name","a")
        .likeRight("email","t");
    List<Map<String, Object>> maps = userMapper.selectMaps(wrapper);
    maps.forEach(System.out::println);
}
日志:
Preparing: 
SELECT id,name,age,email,version,deleted,create_time,update_time 
FROM user 
WHERE deleted=0 
AND (name NOT LIKE ? AND email LIKE ?)
Parameters: %a%(String), t%(String)
5. 通过id进行排序
@Test
public void test5(){
    QueryWrapper<User> wrapper = new QueryWrapper<>();
    wrapper.orderByDesc("id");
    List<User> userList = userMapper.selectList(wrapper);
    userList.forEach(System.out::println);
}
日志:
Preparing: 
SELECT id,name,age,email,version,deleted,create_time,update_time 
FROM user 
WHERE deleted=0
ORDER BY id DESC
6. 子查询
@Test
public void test6(){
    QueryWrapper<User> wrapper = new QueryWrapper<>();
    // id在子查询中查出来
    wrapper.inSql("id","select id from user where id < 3");
    List<User> userList = userMapper.selectList(wrapper);
    userList.forEach(System.out::println);
}
日志:
Preparing: 
SELECT id,name,age,email,version,deleted,create_time,update_time 
FROM user 
WHERE deleted=0 
AND (id IN (select id from user where id < 3))