MyBatisPlus

MyBatisPlus

MyBatisPlus是MyBatis的增强工具。在其基础上不做改变,提高效率。

快速入门

使用

配置:
mybatisplus继承了MyBatis原生配置和特有配置。

mybatis-plus:
  type-aliases-package: com.xxx.domain.po  //需手动指定
  mapper-locations: "classpath*:mapper/**/*.xml"
  global-config:
    db-config:
      id-type: auto
      update-strategy: not_null
  configuration:
    map-underscore-to-camel-case: true
    cache-enable: false

依赖:


        <dependency>
            <groupId>com.baomidougroupId>
            <artifactId>mybatis-plus-boot-starterartifactId>
            <version>3.5.3.1version>
        dependency>

定义Mapper:
myBatisPlus提供了Mapper接口,其中定义了CRUD功能。

public interface UserMapper extends BaseMapper<User> {}

常见注解

MyBatis通过扫描实体类,并基于反射获取实体类信息作为数据库表信息。
约定:

  • 类名驼峰转下划线作为表名。
  • 名为id的字段作为主键
  • 变量名驼峰转下划线作为表的字段名
    @TableName:表名注解,标识实体类对应的表
    @TableId:主键注解,value:名。type:主键类型

AUTO:数据库ID自增
NONE:无状态,该类型为未设置主键类型
INPUT:insert前自行set主键值
ASSIGN_ID:分配ID(主键类型为Numer或String),使用接口IdentifierGenerator的nextId(雪花算法)
ASSIGN_UUID:分配UUID,主键类型为String,使用接口IdentifierGenerator的nextUUID
ID_WORKER:分布式全局唯一ID
UUID:32位UUID字符串
ID_WORKER_STR:分布式全局唯一ID字符串类型

@TableField:字段注解(非主键)使用场景

成员变量名与数据库字段名不一致
成员变量是以isXXX命名,按照JavaBean规范,MyBatisPlus识别字段时会把is去掉,导致与数据库不符
成员变量名与数据库一致,但与数据库关键字冲突,给字段名添加``转义
value:字段名
exist:是否数据库表字段
condition:字段where实体查询比较条件,有值设置则按设置的值为准,没有则位默认全局的$s=#{%s}
update:字段update set部分注入
insertStrategy:注入策略,NOT NULL
updateStragey:更新策略:IGNOED
whereStrategy:查询策略:NOT EMPTY
fill:字段自动填充
select:是否进行select查询
keepGlobalFormat:是都保持使用全局的format进行处理
jdbcType:JDBC类型
typeHandler:类型处理器
numericScale:指定小数点后保留位数
关于jdbcType和typeHandler及numericScale说明:numericScale只生效update,jdbcType和typeHandler如果不配合@TableName#autoResultMap=true一起使用,也只生效与update,对于typeHandler如果字段类型和set进去的类型位equals关系,则只需让你的typeHandler让MyBatis加载到即可,不需要使用注解

核心功能

条件构造器

MyBatisPlus支持各种复杂的where条件。
MyBatisPlus_第1张图片

    @Test
    void testQueryWrapper() {
        QueryWrapper<User> queryWrapper = new QueryWrapper<User>()
                .select("id", "username", "info", "balance")
                .like("username", "o")
                .ge("balance", 1000);
        userMapper.selectList(queryWrapper);
    }
    @Test
    void testLambdaQueryWrapper() {
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        wrapper.lambda().select(User::getId)
                .like(User::getUsername, "o")
                .ge(User::getBalance, 1000);
        userMapper.selectList(wrapper);
    }
    @Test
    void updateWrapper() {
        User user = new User();
        user.setBalance(2000);
        QueryWrapper<User> queryWrapper = new QueryWrapper<User>().eq("username", "aric");
        userMapper.update(user, queryWrapper);
    }
    @Test
    void testUpdateWrapper() {
        UpdateWrapper<User> wrapper = new UpdateWrapper<User>().setSql("balance = balance - 200").in("id", List.of(1, 2, 3));
        userMapper.update(null, wrapper);
    }

自定义SQL

  1. 基于Wrapper构建where条件
    @Test
    void testCustomWrapper(){
        QueryWrapper<User> wrapper = new QueryWrapper<User>()
                .like("username", "o")
                .ge("balance", 1000);
        List<User> users = userMapper.findByCustom(wrapper);
    }
    @Test
    void testUpdateCustomWrapper(){
        List<Integer> ids = List.of(1, 2, 3);
        int amount = 200;
        QueryWrapper<User> wrapper = new QueryWrapper<User>().in("id", ids);
        userMapper.updateBalanceByWrapper(amount, wrapper);
    }
  1. 再mapper方法参数中用Param注解声明wrapper变量名称,必须是ew
    List<User> findByCustom(@Param("ew") QueryWrapper<User> wrapper);

    @Update("update user set balance = balance -  #{amount} ${ew.customSqlSegment}")
    void updateBalanceByWrapper(@Param("amount") int amount, @Param("ew") QueryWrapper<User> wrapper);
  1. 自定义SQL,并使用Wrapper条件
    <select id="findByCustom" resultType="User">
        select * from tb_user ${ew.customSqlSegment}
    select>

Service接口

MyBatisPlus_第2张图片

public interface IUserService extends IService<User> {
}
@Service
//需实现IService中的方法所以继承对应的ServiceImpl
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService {
}

批量新增

  1. 普通for循环逐条插入
  2. MP的批量新增,基于预编译的批处理
  3. 配置jdbc参数,开启rewriteBatchedStatements,性能最优
    在jdbc连接参数后拼接:&rewriteBatchedStatements=true
    底层会在插入时判断rewriteBatchedStatements,如果为true就回重写sql语句

lambdaQuery

    @Test
    void testLambdaQuery() {
        User user = userService.lambdaQuery()
                .eq(User::getUsername, "xxx")
                .one();
    }
        @Test
    void testUpdateBalance(Long balance, Long id) {
        userService.lambdaUpdate()
                .set(User::getBalance, balance)
                .set(balance == 0, User::getStatus, 2)
                .eq(id != null, User::getId, id)
                .update();
    }

静态工具

为避免service循环依赖,在serviceImpl层使用DBaseMapper或者静态工具DB。

拓展功能

代码生成

  1. 快速开发插件:MyBatisX、MyBatisPlus
  2. 在other中config Database配置数据库信息
  3. 在other中Code Generator中选择生成表,填写对应信息即可
    MyBatisPlus_第3张图片

逻辑删除

MyBatisPlus提供逻辑删除,无需改变方法调用的方式,而是底层修改CRUD语句,只需在yml文件中配置逻辑删除字段和值即可。

mybatis-plus:
  global-config:
    db-config:
      logic-delete-field: flag #全局逻辑删除的实体字段名,类型为boolean或integer
      logic-delete-value: 1 #逻辑删除值
      logic-not-delete-value: 0 #逻辑未删除值

如果被删除数据量太大,建议把删除数据迁移到其他表

枚举处理器

直接用枚举类替换状态字段。需要把java的枚举对象转化成数据库的存储类型。之前需要自已定义TypeHandler,现在只需要在枚举类中加@EnumValue注解,并在配一个类型处理器即可。

@Getter
public enum UserStatus {
    NORMAL(1, "正常"),
    FREEZE(2, "冻结"),
    ;
    @EnumValue
    private final int value;
    @JsonValue
    private final String desc;
    UserStatus(int value, String desc) {
        this.value = value;
        this.desc = desc;
    }
}

mybatis-plus:
  configuration:
    default-enum-type-handler: com.baomidou.mybatisplus.core.handlers.MybatisEnumTypeHandler

JSON处理器

  1. 添加依赖
        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starter-jsonartifactId>
        dependency>
  1. json字段加@TableField(typeHandler = JacksonTypeHandler.class)注解,标记json的处理器,并在类上加autoResultMap = true
@TableName(value = "tb_user", autoResultMap = true)
public class User {
    @TableField(typeHandler = JacksonTypeHandler.class)
    private UserInfo info;
}
@Data
@AllArgsConstructor(staticName = "of")
@NoArgsConstructor
public class UserInfo {
    private Integer age;
    private String intro;
    private String gender;
}

配置加密

MyBatisPlus提供一个基于AES算法的加密工具。

    void contextLoads() {
        String randomKey = AES.generateRandomKey();  //生成16位随机AES密钥
        String username = AES.encrypt("root", randomKey);
        String password = AES.encrypt("root", randomKey);
    }

插件功能

MyBatisPlus基于MyBatis的Interceptor实现了一个基础拦截器,并在内部保存了MyBatisPlus的内置拦截器集合。
TenantLineInnerInterceptor:多租户插件
DynamicTableNameInnerInterceptor:动态表名插件
PaginationInnerInterceptor:分页插件
OptimisticLockerInnerInterceptor:乐观锁插件
IllegalSQLInnerInterceptor:SQL性能规范插件,并检测拦截垃圾SQL
BlockArrackInnerInterceptor:防止全表更新和删除插件

分页查询

@Configuration
public class MyBatisConfig {
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor (){
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor(); //创建核心拦截器
        PaginationInnerInterceptor innerInterceptor = new PaginationInnerInterceptor(DbType.MYSQL);  //创建插件
        innerInterceptor.setMaxLimit(1000L);  //上限
        interceptor.addInnerInterceptor(innerInterceptor);
        return interceptor;
    }
}
    void testPageQuery() {
        int pageNo = 1, pageSize = 5;
        Page<User> p = Page.of(pageNo, pageSize);
        p.addOrder(new OrderItem("balance", false));
        Page<User> page = userService.page(p);
    }

你可能感兴趣的:(mybatisplus)