Mybatis-plus

Mybatis-plus

一、快速入门

1、导入Jar包

<!--        驱动-->
        <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.4.2</version>
        </dependency>

**说明:**我们使用 mybatis-plus 可以节省很多时间和代码,尽量不要同时导入mybatis和mybatis-plus版本

2、编写配置文件

# mybatis
spring.datasource.username = root
spring.datasource.password = 2019
spring.datasource.url = jdbc:mysql://localhost:3306/数据库名?useSSL=false&useUnicode=true&characterEncoding=utf-8
spring.datasource.driver-class-name = com.mysql.cj.jdbc.Driver

3、创建实体类

@Data
@AllArgsConstructor
@NoArgsConstructor
public class A_user {
    private Long Id;
    private String name;
    private String password;
}

4、创建Mapper

public interface UserMapper extends BaseMapper<A_user> {

}

5、测试

@Test
void contextLoads() {
    List<A_user> a_users = userMapper.selectList(null);
    a_users.forEach(System.out::println);
}

二、配置日志

我们所有的Sql都是不可见的,我们希望知道是怎么执行的,所以我们必须配置日志

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

三、CRUD扩展

insert 插入 int insert = userMapper.insert(a_user);

数据库生成的ID默认值为:全局的ID

1、主键生成策略

@Test
public void testInset(){
    Admin a_user = new Admin();
    a_user.setName("西奥");
    a_user.setPassword("***");

    int insert = userMapper.insert(a_user);
    System.out.println(insert);
    System.out.println(a_user);
}

@TableId(type = IdType.AUTO)

public enum IdType {
    AUTO(0),	// 数据库自增
    NONE(1),	// 未设置主键
    INPUT(2),	// 手动输入
    ID_WORKER(3),	// 默认的全局ID	
    UUID(4),		// 全局唯一ID
    ID_WORKER_STR(5);		// 字符串

2、更新操作

@Test
public void testUpdate(){
    Admin a_user = new Admin();
    a_user.setId(6L);
    a_user.setName("西奥s");
    a_user.setPassword("***1");
    userMapper.updateById(a_user);
}

所有的sql可以动态配置

3、自动填充

创建时间、修改时间、这个操作一遍都是自动化完成的,我们不希望手动更新!

方式一:数据库级别

1、在表中的新增字段,create_time,update_time

方式二:代码级别

在实体类字符的属性上添加注解

//    字段添加填充内容
    @TableField(fill = FieldFill.INSERT)
    private Date createTime;
//    添加填充内容
    @TableField(fill = FieldFill.INSERT_UPDATE)
    private Date updateTime;

实体类的字段属性要操作注解了

@Slf4j
@Component
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 update fill......");
        this.setFieldValByName("updateTime",new Date(),metaObject);
    }
}
  • @TableField(fill = FieldFill.INSERT):执行添加操作时的自动填充
  • @TableField(fill = FieldFill.INSERT_UPDATE):执行修改操作时的自动填充

4、乐观锁

  • 乐观锁
  • 悲观锁

面试高频

**乐观锁:**顾名思义,十分乐观。总也为不会出现问题,无论干什么不会上锁!如果出现了问题再此更新值测试

**悲观锁:**顾名思义,十分悲观。总也为都会出现问题,无论干什么都会上锁!再去操作

当要更新一条记录的时候,希望这条记录没有被别人更新
乐观锁实现方式:

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

修改表,添加乐观锁。默认值为1

修改实体类,添加乐观锁属性。添加乐观锁注解(代表此字段为乐观锁)

注册组件

修改标和实体类

//    乐观锁
    @Version
    private Integer version;

添加配置文件乐观锁

@MapperScan("com.example.demo.mapper")
@EnableTransactionManagement
@Configuration  // 配置类
public class MybatisPlusConfig {
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
        return interceptor;
    }
}

**总:**如果设置了乐观锁,当用户执行一次修改后,乐观锁会进行一次迭代,当执行增删改会判断version号是否与上次一致,因为每次修改标时,版本也会跟着修改,所以期间有线程进行了修改,就会版本不一致,修改失败

5、查询

  1. 单条通过ID查询

    @Test
    public void testSelectById(){
        Admin admin = userMapper.selectById(2L);
        System.out.println(admin);
    }
    
  2. 多条查询通过数组

    @Test
    public void selectBatchIds(){
        // 查询数组里的ID
        List<Admin> adminList = userMapper.selectBatchIds(Arrays.asList(1, 2, 3));
        adminList.forEach(System.out::println);
    }
    
  3. map条件查询

    @Test
    public void testSelectByBatchIds(){
        HashMap<String, Object> map = new HashMap<>();
        // 自定义要查询的条件
        map.put("name","西奥");
        map.put("password","****");
        userMapper.selectByMap(map);
    }
    

6、分页查询

分页在网站使用的十分之多

1、原始的是使用 limit 进行分页

2、第三方插件 pageHelper

3、MybatisPlus也内置了分页插件!

如何使用MybatisPlus的分页插件

添加分页插件的配置

    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
//        配置乐观锁插件
        interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
//        配置分页插件
        interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.H2));
        return interceptor;
    }

添加测试单元

    @Test
    public void testPage(){
//        参数1:当前页
//        参数2:页面大小
        Page<Admin> objectPage = new Page<>(2,3);
        userMapper.selectPage(objectPage,null);
        objectPage.getRecords().forEach(System.err::println);
    }

7、删除模块

删除单个

//    测试删除
    @Test
    public void testDeleteById(){
        userMapper.deleteById(2L);
    }

删除多个

//    批量删除
    @Test
    public void testDeleteBatchBy(){
        userMapper.deleteBatchIds(Arrays.asList(1,2,3,4));
    }

添加删除

@Test
public void testDeleteMap(){
    HashMap<String, Object> map = new HashMap<>();
    map.put("password","****");
    userMapper.deleteByMap(map);
}

逻辑删除

  • 物理删除:从数据库中直接移除
  • 逻辑删除:在数据库中没有被移除,而是通过一个变量来修改,让它失效,

管理员可以查看已经删除的数据,因为管路员可以查看已经失效的账户,类似于回收站!

1、在数据表中增加deletd字段

2、在实体类中更新字段

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

3、添加配置

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(11L);
}

在进行原来的删除时,会将字段deleted修改为1,代表删除操作

四、性能分析插件

我们在平时的开发中,会遇到一些慢查询

MybatisPlus也提供了性能分析插件,如果超过这个时间就停止运行!

1、导入依赖

<dependency>
    <groupId>p6spy</groupId>
    <artifactId>p6spy</artifactId>
    <version>3.9.1</version>
</dependency>

2、测试使用

spring.datasource.url = jdbc:p6spy:mysql://localhost:3306/security?useSSL=false&useUnicode=true&characterEncoding=utf-8
spring.datasource.driver-class-name = com.p6spy.engine.spy.P6SpyDriver

3、添加设置配置

#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

注意!

  • driver-class-name 为 p6spy 提供的驱动类

  • url 前缀为 jdbc:p6spy 跟着冒号为对应数据库连接地址

  • 打印出sql为null,在excludecategories增加commit

  • 批量操作不打印sql,去除excludecategories中的batch

  • 批量操作打印重复的问题请使用MybatisPlusLogFactory (3.2.1新增)

  • 该插件有性能损耗,不建议生产环境使用。

五、条件构造器

创建对象,用来封装条件

QueryWrapper<Admin> wrapper = new QueryWrapper<>();

设置Wrapper的条件

wrapper.isNotNull("name");
wrapper.isNotNull("password");
wrapper.eq("password","***0");

遍历查出的结果

userMapper.selectList(wrapper).forEach(System.out::println);
  1. 条件查询单个数据

    @Test
    void contextLoads(){
        // 查询name不为空的用户,并且已经删除了的用户
        QueryWrapper<Admin> wrapper = new QueryWrapper<>();
        wrapper.isNotNull("name");		// 不为空的字段
        wrapper.isNotNull("password");	// 不为空的字段
        wrapper.eq("name","西奥50");		// 字段等于
        wrapper.eq("password","***0");		// 字段等于
        userMapper.selectList(wrapper).forEach(System.out::println);
    }
    
  2. 模糊查询

    @Test
    void test3(){
        // 查询名字
        QueryWrapper<Admin> wrapper = new QueryWrapper<>();
        wrapper.likeLeft("name","0")		// 左边模糊
                .likeRight("name","西");		// 右边模糊
        List<Map<String, Object>> maps = userMapper.selectMaps(wrapper);
        maps.forEach(System.out::println);
    }
    
  3. 自定义Sql查询

    @Test
    void test4(){
        // 查询名字
        QueryWrapper<Admin> wrapper = new QueryWrapper<>();
        // id 在子查询中查询出来
        wrapper.inSql("id","select id from admin where id > 50");
        List<Map<String, Object>> maps = userMapper.selectMaps(wrapper);
        maps.forEach(System.out::println);
    }
    
  4. 查询排序

    @Test
    void test6(){
        QueryWrapper<Admin> wrapper = new QueryWrapper<>();
        wrapper.orderByDesc("id");		// 通过ID进行降序排序
        List<Map<String, Object>> maps = userMapper.selectMaps(wrapper);
        maps.forEach(System.out::println);
    }
    
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值