学习笔记-mybatis-plus

概述

官网:MyBatis-Plus (baomidou.com)

特性

  • 无侵入:只做增强不做改变,引入它不会对现有工程产生影响,如丝般顺滑
  • 损耗小:启动即会自动注入基本 CURD,性能基本无损耗,直接面向对象操作
  • 强大的 CRUD 操作:内置通用 Mapper、通用 Service,仅仅通过少量配置即可实现单表大部分 CRUD 操作,更有强大的条件构造器,满足各类使用需求
  • 支持 Lambda 形式调用:通过 Lambda 表达式,方便的编写各类查询条件,无需再担心字段写错
  • 支持主键自动生成:支持多达 4 种主键策略(内含分布式唯一 ID 生成器 - Sequence),可自由配置,完美解决主键问题
  • 支持 ActiveRecord 模式:支持 ActiveRecord 形式调用,实体类只需继承 Model 类即可进行强大的 CRUD 操作
  • 支持自定义全局通用操作:支持全局通用方法注入( Write once, use anywhere )
  • 内置代码生成器:采用代码或者 Maven 插件可快速生成 Mapper 、 Model 、 Service 、 Controller 层代码,支持模板引擎,更有超多自定义配置等您来使用
  • 内置分页插件:基于 MyBatis 物理分页,开发者无需关心具体操作,配置好插件之后,写分页等同于普通 List 查询
  • 分页插件支持多种数据库:支持 MySQL、MariaDB、Oracle、DB2、H2、HSQL、SQLite、Postgre、SQLServer 等多种数据库
  • 内置性能分析插件:可输出 SQL 语句以及其执行时间,建议开发测试时启用该功能,能快速揪出慢查询
  • 内置全局拦截插件:提供全表 delete 、 update 操作智能分析阻断,也可自定义拦截规则,预防误操作

快速开始

新建springboot web项目

导入依赖:尽量不要同时导入mybatis 和mybatis-plus

<!--数据库驱动-->
<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.1</version>
</dependency>

配置连接数据库:

# DataSource Config
spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    #schema: classpath:db/schema-h2.sql
    #data: classpath:db/data-h2.sql
    url: jdbc:mysql://47.113.229.158:3306/mybatis_plus?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=Asia/Shanghai
    username: yang
    password: 123456

编写实体类:

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

编写mapper接口~~~~

@Repository // 代表持久层
//在对应的mapper接口上继承接:BaseMapper 并传入泛型
public interface UserMapper extends BaseMapper<User> {
}

开启mapper扫描 @MapperScan

@MapperScan("com.yang.mapper")//扫描mapper文件夹
@SpringBootApplication
public class SpringbootMybatisplusApplication {

    public static void main(String[] args) {
        SpringApplication.run(SpringbootMybatisplusApplication.class, args);
    }
}

测试:

@Autowired
private UserMapper userMapper;

@Test
void contextLoads() {
    List<User> userList = userMapper.selectList(null);
    for (User user : userList) {
        System.out.println(user);
    }
}

image

配置日志

image

插入测试

User user = new User();
user.setAge(3);
user.setEmail("134679262@qq.com");
user.setName("123");
int insert = userMapper.insert(user);
System.out.println(insert);

插入成功,发现自动生成id!!(要求表名与实体类名一致)

image

主键生成策略

雪花生成算法:(默认)

snowflake是Twitter开源的分布式ID生成算法,结果是一个long型的ID。其核心思想是︰使用41bit作为毫秒数,10bit作为机器的ID(5个bit是数据中心,5个bit的机器ID),12bit作为毫秒内的流水号(意味着每个节点在每毫秒可以产生4096个ID),最后还有一个符号位,永远是0。可以保证几乎全球唯一! I

其他策略: @TableId

@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {

    @TableId(type = IdType.AUTO)
    private Long id;
    private String name;
    private Integer age;
    private String email;
}
  • AUTO 主键自增 需要数据库设置自增
  • NONE 未设置主键
  • INPUT 手动输入

image

更新测试

@Test
void testUpdate(){
    User user = new User();
    user.setId(3L);
    user.setAge(5);
    int update = userMapper.updateById(user);
    System.out.println(update);
}

sql根据参数动态配置~~

image

自动填充

数据库级别(不建议)

image
)

并在实体类中同步

    private Date creat_time;
    private Date update_time;

代码级别

去掉默认值

image

在实体类的属性上设置 @TableField

@TableField(fill = FieldFill.INSERT) //插入时填充
private Date creat_time;
@TableField(fill = FieldFill.UPDATE) //更新时填充
private Date update_time;

自定义填充策略

@Component
@Slf4j
public class MyMetaObjectHandler implements MetaObjectHandler {
    @Override
    public void insertFill(MetaObject metaObject) {
        log.info("start insert fill....");

        this.setFieldValByName("creat_time",new Date(),metaObject);
        this.setFieldValByName("update_time",new Date(),metaObject);
    }

    @Override
    public void updateFill(MetaObject metaObject) {
        log.info("start update fill....");
        this.setFieldValByName("update_time",new Date(),metaObject);
    }
}

乐观锁

乐观锁:故名思意十分乐观,它总是认为不会出现问题,无论干什么不去上锁!如果出现了问题,再次更新值测试

悲观锁:故名思意十分悲观,它总是认为总是出现问题,无论干什么都会上锁!再去操作!|

乐观锁实现方式:

  • 取出记录时,获取当前version
  • 更新时携带version
  • 执行更新操作时,version= new_verison where version = old_version
  • version 不匹配时,更新失败

测试

增加version字段

image

配置version属性 @Version MP的注解

@Version
private Integer version;

注册组件:

@Configuration
//@EnableTransactionManagement  ???官网没有
@MapperScan("com.yang.mapper") 
public class MybatisPlusConfig {
    /**
     * 新版
     */
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor();
        mybatisPlusInterceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
        return mybatisPlusInterceptor;
    }
}

测试:

  • 成功
@Test
    void test1(){
        User user = userMapper.selectById(1487730131458940930L);
        user.setAge(5);
        user.setName("啊啊啊啊");
        int update = userMapper.updateById(user);
    }

先取出后更新,会比较version,成功后version+1

image

  • 失败
@Test
void test2(){
    User user = userMapper.selectById(1487730131458940930L);
    user.setAge(5);
    user.setName("哈哈哈哈");

    //模拟多线程被插队
    User user2 = userMapper.selectById(1487730131458940930L);
    user2.setAge(5);
    user2.setName("1111");
    int update2 = userMapper.updateById(user2);

    int update = userMapper.updateById(user);

}

在没有乐观锁时,这条数据会被 “ 哈哈哈哈 ” 覆盖,但在乐观锁作用下,后面的更新语句失败了

image

注意:

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

查询

多Id查询

@Test
void testquery(){
    List<User> userList = userMapper.selectBatchIds(Arrays.asList(1, 2, 3));
    for (User user : userList) {
        System.out.println(user);
    }
}

map条件查询 不能实现模糊查询

 @Test
    void testquery1(){
        HashMap<String, Object> map = new HashMap<>();
        map.put("name","1111");
        List<User> userList = userMapper.selectByMap(map);
        for (User user : userList) {
            System.out.println(user);
        }
    }

分页查询

   // 最新版
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.H2));
        return interceptor;
    }

使用:

@Test
void testpage(){
    Page<User> page = new Page<>(1,3); //第几页,页面大小

     userMapper.selectPage(page, null);
    page.getRecords().forEach(System.out::println);
}

逻辑删除

物理删除:从数据库中删除

逻辑删除:还在数据库中,通过一个变量来使其失效,防止数据丢失

image

@TableLogic //逻辑删除
private Integer deleted;
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)

实际走的是更新操作,之后查询时会自动拼接 deleted=0 的查询条件,仅查询逻辑未删除的列

性能分析插件?????

生产环境不要用

该功能依赖 p6spy 组件,完美的输出打印 SQL 及执行时长

<dependency>
  <groupId>p6spy</groupId>
  <artifactId>p6spy</artifactId>
  <version>最新版本</version>
</dependency>
  • application.yml 修改:
spring:
  datasource:
    driver-class-name: com.p6spy.engine.spy.P6SpyDriver
    url: jdbc:p6spy:mysql://47.113.229.158:3306/mybatis_plus?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=Asia/Shanghai
  • spy.properties 配置:

    driverlist=com.mysql.cj.jdbc.Driver
    
    logMessageFormat=com.p6spy.engine.spy.appender.MultiLineFormat
    #logMessageFormat=com.p6spy.engine.spy.appender.SingleLineFormat
    
    databaseDialectDateFormat=yyyy-MM-dd HH:mm:ss
    
    appender=com.p6spy.engine.spy.appender.StdoutLogger
    
    
#3.2.1以上使用
modulelist=com.baomidou.mybatisplus.extension.p6spy.MybatisPlusLogFactory,com.p6spy.engine.outage.P6OutageFactory
#3.2.1以下使用或者不配置
#modulelist=com.p6spy.engine.logging.P6LogFactory,com.p6spy.engine.outage.P6OutageFactory
# 自定义日志打印
logMessageFormat=com.baomidou.mybatisplus.extension.p6spy.P6SpyLogger
#日志输出到控制台
appender=com.baomidou.mybatisplus.extension.p6spy.StdoutLogger
# 使用日志系统记录 sql
#appender=com.p6spy.engine.spy.appender.Slf4JLogger
# 设置 p6spy driver 代理
deregisterdrivers=true
# 取消JDBC URL前缀
useprefix=true
# 配置记录 Log 例外,可去掉的结果集有error,info,batch,debug,statement,commit,rollback,result,resultset.
excludecategories=info,debug,result,commit,resultset
# 日期格式
dateformat=yyyy-MM-dd HH:mm:ss
# 实际驱动可多个
#driverlist=org.h2.Driver
# 是否开启慢SQL记录
outagedetection=true
# 慢SQL记录标准 2 秒
outagedetectioninterval=2

image

条件构造器

image

image

  • isNotNull ge
@Test
void test1(){
    QueryWrapper<User> wrapper = new QueryWrapper<>();
    wrapper
        .isNotNull("name")
        .isNotNull("email")
        .ge("age",18); // name、email不为空且age>=18
    userMapper.selectList(wrapper).forEach(System.out::println);
}

image

  • eq
@Test
void test2(){
    QueryWrapper<User> wrapper = new QueryWrapper<>();
    wrapper.eq("name","1111");
    User user = userMapper.selectOne(wrapper);
    System.out.println(user);
}

image

  • between
@Test
void test3(){
    QueryWrapper<User> wrapper = new QueryWrapper<>();
    wrapper.between("age",18,23);
    Long aLong = userMapper.selectCount(wrapper);
    System.out.println(aLong);

}

image

  • notLike likeLeft
 @Test
    void test4(){
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        wrapper.notLike("name","J")
                .likeLeft("name","3"); //   %3

        userMapper.selectMaps(wrapper).forEach(System.out::println);
    }

image

posted @   酷酷丶吖  阅读(39)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· 上周热点回顾(2.24-3.2)
点击右上角即可分享
微信分享提示