MyBatisPlus快速上手

本质

是对mybatis的增强,只做增强不做改变

环境

spring boot

<!--mybatis_plus启动包-->
<dependency>
	<groupId>com.baomidou</groupId>
	<artifactId>mybatis-plus-boot-starter</artifactId>
	<version>3.5.1</version>
</dependency>

<!--mysql驱动包-->
<dependency>
	<groupId>mysql</groupId>
	<artifactId>mysql-connector-java</artifactId>
	<scope>runtime</scope>
</dependency>
spring:
  # 配置数据源信息
  datasource:
    type: com.zaxxer.hikari.HikariDataSource
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/mybatis?serverTimezone=GMT%2B8&characterEncoding=utf-8&userSSL=false
    username: root
    password: root

mybatis-plus:
  configuration:
    # 配置sql日志信息
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
  # 配置类型别名所对应的包
  type-aliases-package: com.xxx.mybatis.domain
  # mybatisplus的全局配置
  global-config:
    db-config:
      # 设置所有实体类所对应的表名的共同前缀
      table-prefix: t_
      # 设置统一主键生成策略
      id-type: assign_id
  # 扫描通用枚举包
  type-enums-package: com.xxx.mybatis.enums

spring boot 启动类增加@MapperScan注解

@SpringBootApplication
//用于扫描mapper接口所在的包
@MapperScan("com.xxx.mybatis.mapper")
public class MybatisApplication {

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

BaseMapper 通用mapper

BaseMapper是mybatisplus提供的类,里面有大量增删改查方法可供使用

public interface UserMapper extends BaseMapper<User> {

}

Iservice 通用service

public interface IUserService extends IService<User> {
}
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService {
}

@TableName

当实体类所对应的数据库表名不一致时,可以使用@TableName标注实体类所对应的表名,如果所有表都有固定前缀,可以在配置文件中设置表名前缀

@Data
@TableName("t_user")
public class User {

    private Long id;
    private String name;
    private Integer age;
    private String email;
}
# yml中配置
# 设置所有实体类所对应的表名的共同前缀
table-prefix: t_

@TableId

可以将这个注解所对应的字段指定为主键
type属性用来定义主键生成策略
IdType.AUTO 设置id自增,但必须保证数据库表id也设置了自增,否则无效
IdType.ASSIGN_ID 雪花算法自动生成id
IdType.ASSIGN_UUID 生成UUID

    @TableId(value = "uid",type = IdType.AUTO)
    private Long id;

通过全局配置设置主键生成策略

# yml中配置
# 设置统一主键生成策略
id-type: assign_id

@TableField

通过@TableField指定属性所对应的字段名

@Data
@TableName("t_user")
public class User {

    @TableId(value = "uid",type = IdType.AUTO)
    private Long id;

    @TableField("user_name")
    private String userName;

    @TableField("age")
    private Integer age;

    @TableField("email")
    private String email;
}

@TableLogic

逻辑删除,假删除,将对应数据中表示删除字段的状态改为被删除状态,在数据库仍旧存在,可以方便之后进行恢复数据

@Data
@TableName("t_user")
public class User {

    @TableId(value = "uid",type = IdType.AUTO)
    private Long id;

    @TableField("user_name")
    private String userName;

    @TableField("age")
    private Integer age;

    @TableField("email")
    private String email;

    @TableLogic
    private Integer isDelete;
}

Wapper queryWapper 条件构造器

查询

@Test
public void select01(){
    //查询所有年龄大于等于20小于等于50且名字带有"测试"的人
    QueryWrapper<User> queryWrapper = new QueryWrapper<>();
    queryWrapper.ge("age",20)
            .le("age",50)
            .like("name","测试");
    List<User> users = userMapper.selectList(queryWrapper);
    users.forEach(System.out::println);
}

删除

@Test
public void delete02(){
	//删除id是1,2,3,4,5的用户
    UpdateWrapper<User> updateWrapper= new UpdateWrapper<>();
    updateWrapper.in("id",1,2,3,4,5);
    int delete = userMapper.delete(updateWrapper);
    System.out.println(delete);
}

修改

@Test
public void update03(){
	//将所有年龄大于等于80或小于等于10的人的邮箱改为"111@qq.com"
	//UPDATE t_user SET email=? WHERE is_delete=0 AND (age >= ? OR age <= ?)
	UpdateWrapper<User> updateWrapper = new UpdateWrapper<>();
	updateWrapper.ge("age",80)
	        .or()
	        .le("age",10);
	User user = new User();
	user.setEmail("111@qq.com");
	int updateResult = userMapper.update(user, updateWrapper);
	System.out.println(updateResult);
}

condition使用方式

queryWrapper.ge(StringUtils.isNotBlank("age"),"age",20);

lambda使用方式

LambdaQueryWrapper<User> lambdaQueryWrapper = new LambdaQueryWrapper<>();
//updateWrapper.in("id",1,2,3,4,5);
lambdaQueryWrapper.in(User::getId,1,2,3,4,5);
userMapper.delete(lambdaQueryWrapper);

分页插件

分页插件配置类,可以把启动类上的@MapperScan放在配置类上

@Configuration
@MapperScan("com.xxx.mybatis.mapper")
public class MyBatisPlusConfig {

    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor(){
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
        return interceptor;
    }
}
@Test
public void select04(){
    Page<User> page = new Page<>(1,3);
    userMapper.selectByPage(page);
}
public interface UserMapper extends BaseMapper<User> {
	Page<User> selectByPage(@Param("page") Page<User> page);
}

乐观锁插件

场景描述

商品单价100,A员工将价格+50,B员工将价格-30,AB同时操作,出现了多读的情况,导致商品价格本应为120,却变成了70,为解决这个情况,使用乐观锁插件,增加了version版本字段

修改MyBatisPlusConfig

@Configuration
@MapperScan("com.xxx.mybatis.mapper")
public class MyBatisPlusConfig {

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

@Version

在版本号字段上增加@version注解

@Data
public class Product {

    @TableId(value = "id",type = IdType.ASSIGN_UUID)
    private Long id;

    @TableField("product_name")
    private String productName;

    @TableField("price")
    private Integer price;

    @Version
    private Integer version;
}

案例

@Test
public void selectA(){
    //A员工查询的商品价格
    Product productA = productMapper.selectById(1);
    System.out.println("A员工查询的商品价格:"+productA.getPrice());

    //B员工查询的商品价格
    Product productB = productMapper.selectById(1);
    System.out.println("B员工查询的商品价格:"+productB.getPrice());

    //A员工将商品价格+50
    productA.setPrice(productA.getPrice()+50);
    productMapper.updateById(productA);

    //B员工将商品价格-30
    productB.setPrice(productB.getPrice()-30);
    productMapper.updateById(productB);

    //老板查询商品价格
    Product productC = productMapper.selectById(1);
    System.out.println("老板查询的商品价格:"+productC.getPrice());
}

结论

增加乐观锁后,A员工将商品价格+50同时修改了版本号,B员工-30时,因为带上的版本号与新版本号不一致,导致update失败,从而避免了修改出错;

通用枚举

修改yml配置

  # 扫描通用枚举包
  type-enums-package: com.xxx.mybatis.enums

user表新增字段sex

创建枚举类

@Getter
@AllArgsConstructor
public enum SexEnum {

  MALE(1,"男"),
  FEMALE(2,"女");
  
  @EnumValue
  private Integer sex;
  private String sexName;
}

User实体类修改

private SexEnum sex;

测试类

    @Test
    public void insertEnum(){
        User user = new User();
        user.setName("小王");
        user.setAge(20);
        user.setSex(SexEnum.FEMALE);
        userMapper.insert(user);
    }

代码生成器

引入依赖

		<dependency>
			<groupId>com.baomidou</groupId>
			<artifactId>mybatis-plus-generator</artifactId>
			<version>3.5.2</version>
		</dependency>

模板

FastAutoGenerator.create("url", "username", "password")
    .globalConfig(builder -> {
        builder.author("baomidou") // 设置作者
            .enableSwagger() // 开启 swagger 模式
            .fileOverride() // 覆盖已生成文件
            .outputDir("D://mybatisplus"); // 指定输出目录
    })
    .packageConfig(builder -> {
        builder.parent("com.baomidou.mybatisplus.samples.generator") // 设置父包名
            .moduleName("system") // 设置父包模块名
            .pathInfo(Collections.singletonMap(OutputFile.xml, "D://mybatisplus")); // 设置mapperXml生成路径
    })
    .strategyConfig(builder -> {
        builder.addInclude("t_simple") // 设置需要生成的表名
            .addTablePrefix("t_", "c_"); // 设置过滤表前缀
    })
    .templateEngine(new FreemarkerTemplateEngine()) // 使用Freemarker引擎模板,默认的是Velocity引擎模板
    .execute();

MyBatisX很好用~

在这里插入图片描述


版权声明:本文为qq_40670787原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。