MyBatisPlus

发布时间 2023-12-13 11:15:06作者: 西芹-小汤圆

入门

安装MySQL依赖的时候出现问题,可以通过添加版本号的方式解决。参考链接

lombok依赖可以用于简化实体类的开发,使用前需要下载lombok插件。

要十分注意版本的适配问题,目前比较推荐使用SpringBoot2版本。

MyBatisPlus生成Sql语句是根据实体类及其属性。

在删除的时候传入id超过int类型的时候,可以在数字后面加上L说明是long型的数据。

依赖文件

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.7.12</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.atguigu</groupId>
    <artifactId>MyBatisPlus-demo</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>MyBatisPlus-demo</name>
    <description>MyBatisPlus-demo</description>
    <properties>
        <java.version>1.8</java.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.5.1</version>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.28</version>
            <scope>runtime</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

配置application.yml

  1. 驱动类driver-class-name:spring boot.2.0(内置jdbc5驱动),驱动类使用: driver-class-name:com.mysql.jdbc.Driver。spring boot2.1及以上(内置jdbc8驱动),驱动类使用: driver-class-name:com.mysql.cj.jdbc.Driver。否则运行测试用例的时候会有WARN信息。
  2. 连接地址url MySQL5.7版本的url: jdbc:mysql://localhost:3306/mybatis_plus?characterEncoding=utf-8&useSSL=false。MySQL8.0版本的url: jdbc:mysql://localhost:3306/mybatis_plus?serverTimezone=GMT%2B8&characterEncoding=utf-8&useSSL=false。否则运行测试用例报告如下错误:java.sql.SQLException:The server time zone value 'ODutexE+a'is unrecognized or represents more
  3. 注意冒号后面空一格。
spring:
  datasource:
    type: com.zaxxer.hikari.HikariDataSource
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/mybatis_plus?characterEncoding=utf-8&useSSL=false
    username: root
    password: 159123zxc

SpringBoot启动类

启动类中指定Mapper所在位置。

@SpringBootApplication
@MapperScan("com.atguigu.mybatisplusdemo.Mapper")
public class MyBatisPlusDemoApplication {

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

}

POJO实体类

使用lombok依赖后,可以直接使用@Data注解实现无参构造、get和set方法还有equal和hash方法的实现。

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

Mapper接口

Mapper接口实现BaseMapper接口后就可以使用里面的方法了。

public interface UserMapper extends BaseMapper<User> {
}

测试文件

@SpringBootTest
public class MyBatisPlusTest {
    @Autowired
    private UserMapper userMapper;

    @Test
    public void testSelectList(){
        List<User> list = userMapper.selectList(null);
        list.forEach(System.out::println);
    }
}

批量删除和批量查询

//批量删除
public void testDelete(){
    List<Long> idLists = Arrays.asList(1L, 2L, 3L);
    int result = userMapper.deleteBatchIds(idLists);
}
//批量添加
public void testSelect(){
    List<Long> idLists = Arrays.asList(1L, 2L, 3L);
    List<User> result = userMapper.selectBatchIds(idLists);
    result.forEach(System.out::println);
}

通用service

通用Service CRUD封装Service接口,进一步封装CRUD采用get查询单行remove删除Iist查询集合page分页前缀命名方式区分Mapper层避免混淆。

MyBatis-Plus中有一个接口IService和其实现类Servicelmpl,封装了常见的业务层逻辑。

UserService

public interface UserService extends IService<User> {
}

UserServiceImpl

public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {
}

测试

public class MyBatisPlusServiceTest {
    @Autowired
    private UserService userService;

    @Test
    public void testGetCount(){
        long count = userService.count();
        System.out.println("总记录数:"+count);
    }
}

批量添加

public void testInsertMore(){
    List<User> list = new ArrayList<>();
    for (int i = 1; i <= 10; i++) {
        User user = new User();
        user.setName("ybc"+i);
        user.setAge(20+i);
        list.add(user);
    }
    boolean b = userService.saveBatch(list);
    System.out.println(b);
}

常用注解

雪花算法

雪花算法能够保证不同表的主键的不重复性,以及相同表的主键的有序性,非常适合分布式系统。

雪花算法总共64bit(一个long型),优点是整体上按照时间递增,并且整个分布式系统内不会产生ID碰撞,并且效率较高。

截图

@TableName

作用于实体类中,用于解决实体类名和数据库表名不一致的问题。

@TableName("t_user")
public class User {
    private Long id;
    private String name;
}

全局配置

application.yml文件中配置统一的前缀,统一的主键生成策略。

mybatis-plus:
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
  #配置mybatisPlus的全局配置
  global-config:
    db-config:
      table-prefix: t_
      id-type: auto

@TableId

MyBatisPlus默认的主键是id,如果需要修改主键,只需将该注解加到属性上,将该属性指定为主键。

@TableId注解的value属性用于解决数据库字段名不一致的问题,type属性是设置主键策略,默认是雪花算法,可以设置为自增,需要先使用truncate table users;命令截断原来的表,并设置为自增才会有效。值得注意的是截断和清空表是不一样的。

public class User {
    @TableId(value = "uid",type = IdType.AUTO)
    private Long id;
    private String name;
}

@TableField

MyBatisPlus会自动将下划线和驼峰命名进行转换。如果是其他情况则需要使用该字段来指定属性所对应的字段名。

public class User {
    private Long id;
    @TableField("user_name")
    private String name;
}

@TableLogic

逻辑删除:假删除,将对应数据中代表是否被删除字段的状态修改为“被删除状态”,之后在数据库中仍旧能看到此条数据记录。

在添加了该注解后,删除是假删除,只是将该位置的值设置为1,可以在数据库中看到该数据。

public class User {
    private String email;
    @TableLogic()
    private Integer isDeleted;
}

条件构造器

Wrapper

  • Wrapper:条件构造器抽象类,最顶端父类
    • AbstractWrapper:用于查询条件封装,生成sql的where条件。
      • QueryWrapper:查询和删除条件封装
      • UpdateWrapper:更新条件封装
      • AbstractLambdaWrapper:使用Lambda语法
        • LambdaQueryWrapper:用于Lambda语法使用的查询Wrapper
        • LambdaUpdateWrapper:Lambda更新封装Wrapper

组装查询条件

public void test01(){
    //查询用户名包含a,年龄在20到30之间,邮箱信息不为uLL的用户信息
    QueryWrapper<User> queryWrapper = new QueryWrapper<>();
    queryWrapper.like("user_name","a")
                    .between("age",20,30)
                            .isNotNull("email");
    List<User> list = userMapper.selectList(queryWrapper);
    list.forEach(System.out::println);
}

条件优先级

lambda表达式中的条件优先执行。

public void test05(){
    //将用户名中包含有a并且(年龄大于20或邮箱为NULL)的用户信息修改
    //lambda表达式中的条件优先执行
    QueryWrapper<User> queryWrapper = new QueryWrapper<>();
    queryWrapper.like("user_name","a")
            .and(i->i.gt("age",20).or().isNull("email"));
    User user = new User();
    user.setName("小红");
    user.setEmail("test@qq.com");
    int result = userMapper.update(user, queryWrapper);
    System.out.println("result"+result);
}

子查询

public void test07(){
    QueryWrapper<User> queryWrapper = new QueryWrapper<>();
    queryWrapper.inSql("uid","select uid from t_user where uid <=100");
    List<User> list = userMapper.selectList(queryWrapper);
    list.forEach(System.out::println);
}

修改数据

UpdateWrapper可以设置查询条件和设置需要修改的内容。

public void test08(){
    UpdateWrapper<User> updateWrapper = new UpdateWrapper<>();
    updateWrapper.like("user_name","a")
            .and(i->i.gt("age",20).or().isNull("email"));
    updateWrapper.set("user_name","小黑").set("email","abc@qq.com");
    int result = userMapper.update(null, updateWrapper);
    System.out.println("result"+result);
}

使用condition组装条件

在方法在填入条件,只有在满足条件后才会进行组装。

public void test09(){
    String username = "";
    Integer ageBegin = 20;
    Integer ageEnd = 30;
    QueryWrapper<User> queryWrapper = new QueryWrapper<>();
    queryWrapper.like(StringUtils.isNotBlank(username),"username",username)
            .ge(ageBegin!=null,"age",ageBegin)
            .le(ageEnd!=null,"age",ageEnd);
    List<User> list = userMapper.selectList(queryWrapper);
    list.forEach(System.out::println);
}

使用LambdaQueryWrapper

因为类的属性名可能与数据库的字段名不一致,所以使用lambda表达式可以减少写错属性的情况。

public void test11(){
    String username = "a";
    Integer ageBegin = null;
    Integer ageEnd = 30;
    LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
    queryWrapper.like(StringUtils.isNotBlank(username),User::getName,username)
            .ge(ageBegin!=null,User::getAge,ageBegin)
            .le(ageEnd!=null,User::getAge,ageEnd);
    List<User> list = userMapper.selectList(queryWrapper);
    list.forEach(System.out::println);
}

插件

分页插件

配置文件

@Configuration
@MapperScan("com.atguigu.mybatisplusdemo.Mapper")
public class MyBatisPlusConfig {

    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor(){
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        //增加分页监视器,并指定数据库类型
        interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
        return interceptor;
    }
}

分页使用

public void testPage(){
    //指定起始页和每页展示的条数
    Page<User> page = new Page<>(1,3);
    userMapper.selectPage(page,null);
}

自定义分页

自定义分页只需设置函数的第一个参数和返回值为Page<T>类型,则可以自动完成分页操作。

<!--    Page<User> selectPageVo(@Param("page") Page<User> page, @Param("age") Integer age);-->
<select id="selectPageVo" resultType="User">
    select uid,user_name,age,email from t_user where age > #{age}
</select>

乐观锁插件

乐观锁实现步骤:在数据库中添加version字段,取出记录时,获取当前version,更新时,version+1,如果where语句中的version版本不对,则更新失败。

在配置文件中的监视器增加乐观锁插件:interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());,并且在实体类的version属性上添加@Version注解。

通用枚举

当使用枚举类型时需要添加@EnumValue注解,将注解所标识的属性的值存储到数据库中,还需要在application.yml文件中配置扫描通用枚举的包:type-enums-package: com.atguigu.mybatisplusdemo.enums

代码生成器

引入依赖

<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-generator</artifactId>
    <version>3.5.1</version>
</dependency>
<dependency>
    <groupId>org.freemarker</groupId>
    <artifactId>freemarker</artifactId>
    <version>2.3.31</version>
</dependency>

快速生成

public class FastAutoGeneratorTest {

    public static void main(String[] args) {
        FastAutoGenerator.create("jdbc:mysql://localhost:3306/mybatis_plus?characterEncoding=utf-8&useSSL=false", "root", "159123zxc")
                .globalConfig(builder -> {
                    builder.author("xiqin") // 设置作者
                            //.enableSwagger() // 开启 swagger 模式
                            .fileOverride() // 覆盖已生成文件
                            .outputDir("D://mybatis_plus"); // 指定输出目录
                })
//                .dataSourceConfig(builder -> builder.typeConvertHandler((globalConfig, typeRegistry, metaInfo) -> {
//                    int typeCode = metaInfo.getJdbcType().TYPE_CODE;
//                    if (typeCode == Types.SMALLINT) {
//                        // 自定义类型转换
//                        return DbColumnType.INTEGER;
//                    }
//                    return typeRegistry.getColumnType(metaInfo);
//
//                }))
                .packageConfig(builder -> {
                    builder.parent("com.atguigu") // 设置父包名
                            .moduleName("MyBatisPlusdemo") // 设置父包模块名
                            .pathInfo(Collections.singletonMap(OutputFile.mapperXml, "D://mybatis_plus")); // 设置mapperXml生成路径
                })
                .strategyConfig(builder -> {
                    builder.addInclude("t_user") // 设置需要生成的表名
                            .addTablePrefix("t_", "c_"); // 设置过滤表前缀
                })
                .templateEngine(new FreemarkerTemplateEngine()) // 使用Freemarker引擎模板,默认的是Velocity引擎模板
                .execute();
    }
}

MyBatisX插件

MyBatis-Plus为我们提供了强大的mapper和service模版,能够大大的提高开发效率。但是在真正开发过程中,MyBatis-Plus并不能为我们解决所有问题,例如一些复杂的SQL,多表联查,我们就需要自己去编写代码和SQL语句,这个时候可以使用MyBatisX插件MyBatisX,一款基于IDEA的快速开发插件,为效率而生。

点击小鸟图标可以在接口和对应的xml文件之间快速跳转。

使用的时候首先登录idea自带的database,然后打开对应的表,右键选择MyBatisX-Generator,然后填写参数即可。

编写方法也十分方便,只需在接口中声明有小鸟图标的方法,然后ALT+enter选择生成即可。