MyBatis plus

MyBatis-Plus (opens new window)(简称 MP)是一个 MyBatis (opens new window)的增强工具,在 MyBatis 的基础上只做增强不做改变,为简化开发、提高效率而生。

我们将通过一个简单的 Demo 来阐述 MyBatis-Plus 的强大功能,在此之前,我们假设您已经:

拥有 Java 开发环境以及相应 IDE

熟悉 Spring Boot

熟悉 Maven


1. 创建数据库和表

2.创建项目,初始化项目,使用SpringBoot初始化!

 3.导入依赖

   <!--数据库驱动-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.47</version>
        </dependency>
        <!--lombok-->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.22</version>
        </dependency>
        <!--mybatis-plus-->
        <!--mybatis-plus是自己开发的,并非官方的!-->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.0.5</version>
        </dependency>

我们使用mybatis-plus 可以节省我们大量的代码,尽量不要同时导入mybatis和mybatis-plus因为版本有差异!

4.在 application.yml 配置文件连接数据库!这一步和mybatis相同!

# 应用名称
spring.application.name=mybatis_plus_01
# 应用服务 WEB 访问端口
server.port=8080

# mysql 5 驱动不同  com.mysql.jdbc.Driver
spring.datasource.username=root
spring.datasource.password=root
spring.datasource.url=jdbc:mysql://localhost:3306/mybatis_plus?useSSL=false&useUnicode=true&characterEncoding=utf-8
spring.datasource.driver-class-name=com.mysql.jdbc.Driver


# mysql 8 驱动不同 com.mysql.cj.jdbc.Driver . 需要增加时区的配置 serverTimezone=GMT%2B8
#spring.datasource.url=jdbc:mysql://localhost:3306/mybatis_plus?useSSL=false&useUnicode=true&characterEncoding=utf-8&serverTimezone=GMT%2B8
#spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
# 日志
mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl

 5.传统的方式pojo-dao(连接mybatis,配置mapper.xml文件)-service-controller

使用了mybatis-plus之后

pojo

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

mapper接口  

/**
 * 既然对mybatis增强,就要有所行动。
 * 如想要增删改查,不需要这样写接口了,
 *
 * 直接继承BaseMapper<对哪个表做操作,泛型就行哪个表>
 *     BaseMapper点就去可以看到,所有的增删改查的接口都已经写好了
 */
@Repository    //交给我们的spring容器管理,代表它是一个持久层
public interface UserMapper extends BaseMapper<User> {

    //所有的CRUD已经基本上完成了

    //但是如果想要添加一些独有的方法,也是可以自己写的(编写自己的接口)

    //List<User> findAll();  //查询所有
}

注意点:我们需要在主启动类上去扫描我们的mapper包下的所有接口  

@SpringBootApplication
@MapperScan("com.lxyk.mapper")     //直接扫描路径包所在的接口,如果没有,每个接口都要加@mapper注解 (写完直接去测试)
public class MybatisPlus01Application {

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

}

测试类中测试

@SpringBootTest
class MybatisPlus01ApplicationTests {
//直接把接口注入进来
    @Autowired
    private UserMapper userMapper;   //不需要写实现类的xml了(单表不用)
    @Test
    void contextLoads() {
        //直接调用查询方法,但是这个方法中有这个参数是我们没有的 Wrapper<T>(它代表的是实体对象封装类,可以为null)
        userMapper.selectList(null).forEach(System.out::println);//返回一个list,所以遍历
    }

}

配置日志

# 配置日志 (系统自带的,控制台输出)
mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl

2. 主键生成策略

主键自增

我们需要配置主键自增:

  1. 实体类字段上 @TableId(type = IdType.AUTO)

  2. 数据库字段上一定是自增的

AUTO,       //数据库id自增
NONE,       //为设置主键
INPUT,      // 手动输入   自己写id
ID_WORKER,  // 默认的全局唯一id
UUID,       // 全局唯一id  UUID
ID_WORKER_STR; // ID_WORKER 字符串的表示

@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
    //对应数据库中的主键(uuid,自增id,雪花算法,redis,zookeeper!)
    @TableId(type = IdType.INPUT)  //一旦收到输入id之后,就需要自己配置id了!
    private Long id;
    private String name;
    private Integer age;
    private String email;
}
 //测试插入
    @Test
    public void testInsert() {
        User user = new User(6L,"fbb4",18,"test9@baomidou.com");
        System.out.println(userMapper.insert(user));
    }

自动填充

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

阿里巴巴开发手册:所有的数据库表:gmt_create、gmt_modified几乎所有的表都要配置上!而且需要自动化!

我们需要在实体类中定义两个字段

private Date createTime;
private Date updateTime; 

然后在字符段的上方加入注解

//  插入填充字段

@TableField(.. fill = FieldFill.INSERT) 

private Date createTime;

//  插入和更新填充字段
@TableField(fill = FieldFill.INSERT_UPDATE)
private Date updateTime;  

 /**
     * 默认不处理
     */
    DEFAULT,
    /**
     * 插入填充字段
     */
    INSERT,
    /**
     * 更新填充字段
     */
    UPDATE,
    /**
     * 插入和更新填充字段
     */
    INSERT_UPDATE

在表中新增字段 create_time,update_time

 

编写一个类的处理器来处理这个注解即可  

@Slf4j       //日志注解
@Component  // 一定不要忘记把处理器加到IOC容器中
public class MyMetaObjectHandler implements MetaObjectHandler {
    // 插入时候的填充策略
    @Override
    public void insertFill(MetaObject metaObject) {
        log.info("start insert fill ...");
        // setFieldValByName(String fieldName, Object fieldVal, MetaObject metaObject)
        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);
    }
}

 继承MetaObjectHandler,实现它的两个方法


乐观锁(面试常问)

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

悲观锁:顾名思义,它总是认为总是出现问题,无论干什么都上锁!再去操作!

 .配置插件

spring xml 方式:

<bean class="com.baomidou.mybatisplus.extension.plugins.inner.OptimisticLockerInnerInterceptor" id="optimisticLockerInnerInterceptor"/>

<bean id="mybatisPlusInterceptor" class="com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor">
    <property name="interceptors">
        <list>
            <ref bean="optimisticLockerInnerInterceptor"/>
        </list>
    </property>
</bean>

spring boot 注解方式:

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

然后需要在实体类和数据库当中添加字段

@Version
private Integer version;  //乐观锁

  注册组件

// 扫描我们的 mapper文件夹
@MapperScan("com.lxyk.mapper")
@EnableTransactionManagement  //开启事务支持
@Configuration  //配置类
public class MyBatisPlusConfig {
    
    // 注册乐观锁插件
    @Bean
    public OptimisticLockerInterceptor optimisticLockerInterceptor() {
        return new OptimisticLockerInterceptor();
    }
}
// Spring Boot 方式
@Configuration
@MapperScan("按需修改")
public class MybatisPlusConfig {
    /**
     * 旧版
     */
    @Bean
    public OptimisticLockerInterceptor optimisticLockerInterceptor() {
        return new OptimisticLockerInterceptor();
    }

    /**
     * 新版
     */
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor();
        mybatisPlusInterceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
        return mybatisPlusInterceptor;
    }
}

新旧版本对比,案例是旧版

测试一下

 // 测试乐观锁成功
    @Test
    public void testVersionSuccess(){
        // 1. 查询用户信息
        User user = userMapper.selectById(1L);
        // 2. 修改用户信息
        user.setName("fbb");
        user.setAge(24);
        // 3. 执行更新操作
        userMapper.updateById(user);
    }

    // 测试乐观锁失败!多线程下
    @Test
    public void testVersionFall(){
        // 线程1
        User user1 = userMapper.selectById(1L);
        user1.setName("fan111");
        user1.setAge(14);

        // 线程2
        User user2 = userMapper.selectById(1L);
        user2.setName("fan222");
        user2.setAge(24);
        userMapper.updateById(user2);

        //自旋锁来多次尝试提交!
        userMapper.updateById(user1); //如果没有乐观锁就会覆盖插队线程的值
    }

乐观锁成功

乐观锁失败

查询操作

 //测试查询
    @Test
    public void testSelectById(){
        User user = userMapper.selectById(1L);
        System.out.println(user);
    }
    // 批量查询
    @Test
    public void testSelectByBatchIds(){
        List<User> users = userMapper.selectBatchIds(Arrays.asList(1, 2, 3));
        users.forEach(System.out::println);
    }

    // 按照条件查询之一使用 map
    @Test
    public void testSelectByMap(){
        HashMap<String, Object> map = new HashMap<>();
        // 自定义要查询
        map.put("name","冯宝宝说java");
        map.put("age",3);
        List<User> users = userMapper.selectByMap(map);
        users.forEach(System.out::println);
    }

分页查询

1.配置拦截器

// 分页插件
@Bean
public PaginationInterceptor paginationInterceptor() {
    return new PaginationInterceptor();
}

可以和之前的乐观锁注册写在一起 

2.直接使用Page对象即可

    //分页
    @Test
    public void test6(){
        // 当前页
        // 每页显示条数
        Page<User> page = new Page<>(1,5);
        userMapper.selectPage(page,null);

        page.getRecords().forEach(System.out::println);

        System.out.println(page.getTotal());  //总数
    }

删除操作

删除分两种,物理删除和逻辑删除

物理删除是真删除

逻辑删除不会真的删除,查询是查不到的,但数据依然存在于数据库中,只是字段状态改变了

  • 逻辑删除是为了方便数据恢复和保护数据本身价值等等的一种方案,但实际就是删除。
  • 如果你需要频繁查出来看就不应使用逻辑删除,而是以一个状态去表示。

逻辑删除:

1.配置文件application.yml

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)

2. 实体类字段上加上@TableLogic注解(数据库也要加)


@TableLogic
private Integer deleted;

3.注册层去注册逻辑删除(和乐观锁、分页写在一起)

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

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

    // 测试批量删除
    @Test
    public void testDeleteBatchId(){
        userMapper.deleteBatchIds(Arrays.asList(1287326823914405893L,1287326823914405894L));
    }

    //通过map删除
    @Test
    public void testDeleteByMap(){
        HashMap<String, Object> map = new HashMap<>();
        map.put("name","冯宝宝说java");
        userMapper.deleteByMap(map);
    }

性能插件

 sql执行效率插件

它可以执行检测每条sql语句大概在什么范围,是否需要优化

1.首先要注册(在注册层里写)

    @Bean
    @Profile({"dev","test"})  //设置dev(开发)  test(测试)  环境开启,保证我们的效率 (在yml文件中开启设定)
    public PerformanceInterceptor performanceInterceptor(){
        PerformanceInterceptor performanceInterceptor = new PerformanceInterceptor();
        performanceInterceptor.setMaxTime(100); //(ms==毫秒) 设置sql执行的最大时间,如果超过了则不执行
        performanceInterceptor.setFormat(true); // 是否格式化
        return performanceInterceptor;
    }

 2.配置文件application.yml

在spring:中加入

profiles:
    active: dev
spring:
    application:
        name: mybatis_plus_01
    datasource:
        driver-class-name: com.mysql.jdbc.Driver
        password: root
        url: jdbc:mysql://localhost:3306/mybatis_plus?useSSL=false&useUnicode=true&characterEncoding=utf-8
        username: root
    # 开启 设置 SQL执行效率插件
    profiles:
        active: dev

 测试一下

    @Test
    public void test10(){
        //这条sql如果在设定的10毫秒之内, 就正常查出来,如果超时就会抛异常
        userMapper.selectList(null).forEach(System.out::println);
    }

注意:

打开浏览器,搜索任意数据,点进去后不会超过2秒。因为在实际开发中,超过两秒就要去修改这个接口了(涉及到sql优化)sql语句优化的30种方法 - littlecarzz - 博客园


条件构造器

  可按条件去查询

    //条件构造器
    @Test
    public void test11(){
        //查询name不为空,邮箱不为空,年龄大于10岁
        QueryWrapper<User> Wrapper = new QueryWrapper<>();
        Wrapper.isNotNull("name").isNotNull("email").gt("age",10);  //查询条件
        userMapper.selectList(Wrapper).forEach(System.out::println);
    }

使用 QueryWrapper 是mybatis-plus 不写SQL就可以完成查询的一个工具类

https://www.csdn.net/tags/NtzaEg2sMTMxNjYtYmxvZwO0O0OO0O0O.html

条件构造器 | MyBatis-PlusMyBatis-Plus 官方文档https://baomidou.com/pages/10c804/#abstractwrapper打开官网,搜索条件构造器,便可知道有那些方法来帮助查询

部分方法演示:

package com.lxyk;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.lxyk.mapper.UserMapper;
import com.lxyk.pojo.User;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@SpringBootTest
class MybatisPlus01ApplicationTests {

    //条件构造器
    //isNotNull
    @Test
    public void test11(){
        //查询name不为空,邮箱不为空,年龄大于10岁
        QueryWrapper<User> Wrapper = new QueryWrapper<>();
        Wrapper.isNotNull("name").isNotNull("email").gt("age",10);  //查询条件
        userMapper.selectList(Wrapper).forEach(System.out::println);
    }
    //eq
    @Test
    public void test12(){
        //查询姓名为Tom
        QueryWrapper<User> Wrapper = new QueryWrapper<>();
        Wrapper.eq("name","Tom");
        User user = userMapper.selectOne(Wrapper);//多条数据List或者map
        System.out.println("user="+user);
    }
    //between
    @Test
    public void test13(){
        //查询数据之前的区间 如:20------30之间的用户
        QueryWrapper<User> Wrapper = new QueryWrapper<>();
        Wrapper.between("age",20,30);
        Integer Count = userMapper.selectCount(Wrapper);
        System.out.println("Count="+Count);
    }
    //notLike
    @Test
    public void test14(){
        //查询name 不包含m的  邮箱是t开头的
        QueryWrapper<User> Wrapper = new QueryWrapper<>();
        Wrapper.notLike("name","m").likeRight("email","t");   //likeRight == '值%';likeLeft == '%值';notLike == ‘%值%’
        List<Map<String, Object>> Count = userMapper.selectMaps(Wrapper);//多条数据List或者map
        Count.forEach(System.out::println);
    }
    //inSql
    @Test
    public void test15(){
        //查询name 不包含m的  邮箱是t开头的
        QueryWrapper<User> Wrapper = new QueryWrapper<>();
        Wrapper.inSql("id","select id from user where id < 3");   //id小于3的语句
        List<Object> list = userMapper.selectObjs(Wrapper);
        list.forEach(System.out::println);
    }
    //排序(升或倒)
    @Test
    public void test16(){
        //查询name 不包含m的  邮箱是t开头的
        QueryWrapper<User> Wrapper = new QueryWrapper<>();
        //Wrapper.orderByDesc("id");  //倒序
        Wrapper.orderByAsc("id");   //升序
        List<User> list = userMapper.selectList(Wrapper);
        list.forEach(System.out::println);
    }
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值