Bootstrap

MybatisPlus--小结

MybatisPlus–小结

详细内容请查看官方文档

一、简介

是一个 MyBatis 的增强工具,在 MyBatis 的基础上只做增强不做改变,为简化开发、提高效率而生。

框架结构

在这里插入图片描述

注解
名称用途
@TableName用在实体类上,描述表名。可以解决表名和实体类名不一致情况
@TableId描述主键字段上,可配置主键生成策略
@TableField表字段描述
@Version标记乐观锁字段
@EnumValue注解在枚举字段上【没用过
@TableLogin标记逻辑删除字段
@SqlParser租户注解,支持method上以及mapper接口上【没用过
@KeySequence序列主键策略

二、快速入门

1.先导入依赖

        <!-- mysql -->
	    <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>

        <!-- mybatis-plus-->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.0.5</version>
        </dependency>

2.配置数据信息

# mysql8 需要配置时区信息 serverTimezone=UTC
spring:
  datasource:
    username: root
    password: admin
    url: jdbc:mysql:///test?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8
    driver-class-name: com.mysql.cj.jdbc.Driver

3.编写mapper继承BaseMapper

BaseMapper由mybatis-plus提供,里面提供了一些基本的增删改查操作

@Repository
public interface UserMapper extends BaseMapper<User> {
}

在这里插入图片描述

4.然后就可以直接注入使用了

@RunWith(SpringRunner.class)
@SpringBootTest
public class ApplicationTest {
    @Autowired
    private UserMapper userMapper;
    @Test
    public void test(){
        // 参数是一个Wrapper,条件构造器,使用null,表示查询所有
        List<User> userList = userMapper.selectList(null);
        userList.forEach(System.out::println);
    }
}

三、 配置日志

配置文件中添加配置即可

# 配置日志-控制台输入             
mybatis-plus:
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl  # 日志控制台 输出

四、CRUD扩展

4.0 主键生成策略
public enum IdType {
    AUTO(0),   // 主键自增   需要配置数据库主键自增
    NONE(1),   // 未设置主键
    INPUT(2),  // 手动输入,也可以使用自定义id生成器
    ID_WORKER(3),   // 雪花算法,默认使用这个,
    UUID(4),    // 全局唯一uuid
    ID_WORKER_STR(5);   // ID_WORKER的字符串表示法
}
4.1 Insert操作
// 插入一条记录,可配置id填充策略
int insert(T entity);
4.2 update操作
    // 根据 ID 修改
    int updateById(T entity);

 	// 根据 wrapper 条件,更新
    int update(T entity, Wrapper<T> updateWrapper);
4.3 字段自动填充
  • 数据库级别自动填充
  • 代码级别自动填充

示例:以自动填充创建时间和更新时间为例

1)数据库级别自动填充

时间字段需要默认值,然后update_time字段,需要勾选更新

在这里插入图片描述

2)代码级别自动填充
  1. 在实体类对应字段使用@TableField注解
填充策略
public enum FieldFill {
   	// 不填充
    DEFAULT,
    // 插入时填充
    INSERT,
    // 更新时填充
    UPDATE,
    // 插入和更新时填充字段
    INSERT_UPDATE
}

使用示例:

@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
    @TableId(type = IdType.INPUT)  // 主键生成策略--自己输入
    private Long id;
    private String name;
    private Integer age;
    private String email;

    // fill 自动填充策略
    @TableField(fill = FieldFill.INSERT)    // 插入时自动填充 createTime字段
    private Date createTime;
    @TableField(fill = FieldFill.INSERT_UPDATE)
    private Date updateTime;
}
  1. 编写实现MetaObjectHandler
@Slf4j
@Component //放入容器中
public class MyMetaObjectHandler 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) {
        // 参数:字段名,插入数据,metaObject
        this.setFieldValByName("updateTime",new Date(),metaObject);
    }
}
4.4 乐观锁

简述:总是认为当前操作不会出现问题,只有数据进行提交更新的时,才会对数据的冲突与否进行检测,如果发现冲突了,则返回给用户错误的信息,让用户决定如何去做。

乐观锁实现方式:

  • 取出记录时,获取当前version
  • 更新时,带上这个version
  • 执行更新时,如果当前记录的version与我们携带的version相同的话。更新成功–>version+1、否则更新失败

悲观锁:认为当前操作总会出现问题,所以每次都上锁,防止并发。(行级锁

注意:

  • 支持的数据类型只有:int,Integer,long,Long,Date,Timestamp,LocalDateTime
  • 整数类型下 newVersion = oldVersion + 1
  • newVersion 会回写到 entity
  • 仅支持 updateById(id)update(entity, wrapper) 方法
  • update(entity, wrapper) 方法下, wrapper 不能复用!!!

1.表添加version字段

2.实体类添加version字段,加上@Version注解

    @Version // 乐观锁Version字段
    private Integer version;

3.编写配置文件,添加乐观锁组件

@MapperScan("top.roise.mapper")
@EnableTransactionManagement  // 配置事务
@Configuration
public class MyBatisPlusConfig {
    // 注册乐观锁插件
    @Bean
    public OptimisticLockerInterceptor optimisticLockerInterceptor(){
        return new OptimisticLockerInterceptor();
    }
}

4.测试更新操作

/**
 * 单线程
 * 测试乐观锁
 */
@Test
public void testOptimisticLockerInterceptor(){
    User user = userMapper.selectById(1);
    user.setName("88pp88");

    int i = userMapper.updateById(user);
    System.out.println(i);
}

更新的时候会判断version,如果和原来相同,则更新成功。version+1

在这里插入图片描述

模拟多线程

    @Test
    public void testOptimisticLockerInterceptor(){
        User user = userMapper.selectById(1);
        user.setName("yyy666");

        // (模拟多个用户更新)测试插入     如果没有乐观锁,第二次更新会覆盖第一次更新的值
        User user2 = userMapper.selectById(1);
        user.setName("mmm55");
        userMapper.updateById(user2);

        int i = userMapper.updateById(user);
        System.out.println(i);
    }

在这里插入图片描述

4.5 查询操作
selectById(Serializable id)根据 ID 查询
selectBatchIds(Collection ids)根据ID 批量查询
selectByMap(Map map)条件查询,把查询条件放map里面

   // 条件查询--使用map
    @Test
    public void testSelectByMap(){
        HashMap<String, Object> map = new HashMap<>();

        // 查询条件  --会拼接到where
        map.put("name","中心小学");
        map.put("age", "122");

        List<User> users = userMapper.selectByMap(map);
        users.forEach(System.out::println);
    }

在这里插入图片描述

4.6 分页查询

1.配置分页插件

步骤:1.添加配置组件 2.selectPage()方法

   // Mybatis-Plus 配置类中---
   // 分页插件
    @Bean
    public PaginationInterceptor paginationInterceptor() {
        return new PaginationInterceptor();
    }
  	// import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
	// 分页查询
    @Test
    public void testFenYe(){
        // 当前页 页面显示的行数
        Page<User> page = new Page<>(2,5);
        userMapper.selectPage(page,null);
    }
4.7 删除操作
int deleteById(Serializable id);根据 ID 删除
int deleteBatchIds(Collection<? extends Serializable> idList);根据ID 批量删除
int deleteByMap(Map<String, Object> columnMap);根据 columnMap 条件,删除记录
int delete(Wrapper queryWrapper);根据wrapper条件删除
    // 示例
    @Test
    public void testDeleted(){
        // 删除单条
        int i = userMapper.deleteById(90L);
        System.out.println(i);

        // 批量通过id删除
        int i1 = userMapper.deleteBatchIds(Arrays.asList(4, 5));
        System.out.println(i1);
        
        // 通过map添加条件删除
        HashMap<String, Object> map = new HashMap<>();
        map.put("name","lisbai");
        int i2 = userMapper.deleteByMap(map);
        
   		// wrapper条件删除
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        wrapper.eq("email","[email protected]");
        userMapper.delete(wrapper);
    }

五、逻辑删除

1.数据库添加逻辑删除字段deleted【int ,1位, 默认0】

2.pojo添加相应字段,加上注解@TableLogic

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

3.配置类添加逻辑删除组件

    // 逻辑删除
    @Bean
    public ISqlInjector iSqlInjector(){
        return new LogicSqlInjector();
    }

4.配置文件添加

mybatis-plus:
  global-config:
    db-config:
      logic-delete-field: deleted  # 全局逻辑删除的实体字段名 
      logic-delete-value: 1 # 逻辑已删除值(默认为 1)
      logic-not-delete-value: 0 # 逻辑未删除值(默认为 0)

5.测试

    @Test
    public void testLogic(){
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        wrapper.eq("email","[email protected]");
        userMapper.delete(wrapper);
    }

在这里插入图片描述

六、条件构造器Wrapper

示例1:多条件查询

select x,x,x from user where name != null and eamil != null and age < 8

    // 查询姓名不为空,邮箱不为空,并且age<8
    @Test
    public void test1(){
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        wrapper
                .isNotNull("name")
                .isNotNull("email")
                .le("age",8L);
        List<User> users = userMapper.selectList(wrapper);
    }

示例2:只查询出一个对象

select x,x,x from user where name = "Tom"

   // 查询一个
    @Test
    public void test2(){
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        wrapper.eq("name","Tom");
        User user = userMapper.selectOne(wrapper);
    }

示例3:范围查询

select x,x,x from user where deleted = 0 and age between 20 and 30

    // 查询年龄在20~30的人数
    // SELECT COUNT(1) FROM user
    // WHERE deleted=0 AND age BETWEEN 20 AND 30        
    @Test
    public void test3(){
        QueryWrapper<User> wrapper = new QueryWrapper<>();

        wrapper.between("age",20,30);  // 字段+区间
        Integer count = userMapper.selectCount(wrapper);

        System.out.println(count);
    }

示例4:模糊查询

    // 模糊查询
    // like --> %AA%   likeRight--> AA%   likeLeft--> %BB
    @Test
    public void test4(){
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        wrapper.like("name","App") // %App%  name包含9
                .likeRight("email","122");  // 122%  email中以122开头的

        List<Map<String, Object>> maps = userMapper.selectMaps(wrapper);
        maps.forEach(System.out::println);
    }

示例5:子查询

SELECT ... FROM user WHERE deleted=0 AND id IN (select id from user where id < 3)

QueryWrapper<User> wrapper = new QueryWrapper<>();
// 建立子查询  要查询的id在子查询里面
wrapper.inSql("id","select id from user where id < 3");

更多用法参考官方文档

在这里插入图片描述

;