Mybatis-Plus

说明

  • Mybatis-Plus:是一个 MyBatis 的增强工具,在 MyBatis 的基础上只做增强不做改变,为简化开发、提高效率而生。
  • 官方文档:https://baomidou.com/
  • mybatis-plus版本:3.5.1(不要用3.5.2版本,有些坑。比如通用枚举的数据存取不行)
辅助 描述
Mybatis Plus Generator 代码生成器
MybatisX 主要用于XML代码生成

优点

  • 无侵入:只做增强不做改变,引入它不会对现有工程产生影响,如丝般顺滑
  • 损耗小:启动即会自动注入基本 CURD,性能基本无损耗,直接面向对象操作
  • 强大的 CRUD 操作:内置通用 Mapper、通用 Service,仅仅通过少量配置即可实现单表大部分 CRUD 操作,更有强大的条件构造器,满足各类使用需求
  • 支持 Lambda 形式调用:通过 Lambda 表达式,方便的编写各类查询条件,无需再担心字段写错
  • 支持主键自动生成:支持多达 4 种主键策略(内含分布式唯一 ID 生成器 - Sequence),可自由配置,完美解决主键问题
  • 支持 ActiveRecord 模式:支持 ActiveRecord 形式调用,实体类只需继承 Model 类即可进行强大的 CRUD 操作
  • 支持自定义全局通用操作:支持全局通用方法注入( Write once, use anywhere )
  • 内置分页插件:基于 MyBatis 物理分页,开发者无需关心具体操作,配置好插件之后,写分页等同于普通 List 查询
  • 分页插件支持多种数据库:支持 MySQL、MariaDB、Oracle、DB2、H2、HSQL、SQLite、Postgre、SQLServer 等多种数据库
  • 内置性能分析插件:可输出 SQL 语句以及其执行时间,建议开发测试时启用该功能,能快速揪出慢查询
  • 内置全局拦截插件:提供全表 delete 、 update 操作智能分析阻断,也可自定义拦截规则,预防误操作

1. 应用

(1)导入依赖

  • 说明:mybatis-plus依赖导入后无需导入mybatis依赖
<dependency>
    <groupId>com.baomidougroupId>
    <artifactId>mybatis-plus-boot-starterartifactId>
    <version>3.5.1version>
dependency>

(2)配置

  • 说明:
    • 新版本,默认使用下划线转驼峰方式
    • 配置基本与mybatis一致(将mybatis.xxx换为mybtis-plus.xxx便可)
spring:
  datasource:
    username: root
    password: 13106777006
    url: jdbc:mysql://localhost:3306/demosql?useUnicode=true&characterEncoding=UTF-8
    driver-class-name: com.mysql.cj.jdbc.Driver

mybatis-plus:
  configuration:
    # sql日志配置,目的:发送的sql在终端显示
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
#    关系映射文件扫描
  mapper-locations: classpath*:mybatis/mapper/*.xml
#  对象别名设置
  type-aliases-package: com.beholder1234.springbootproject1.pojo

(3)编写Mapper接口

@Mapper
@Repository
// BaseMapper 实现有一些基础的sql方法,返回Goods类
public interface GoodsMapper  extends BaseMapper<Goods> {

}

(4)测试

@SpringBootTest
class Springbootproject1ApplicationTests {
    @Autowired
    GoodsMapper goodsMapper;

    @Test
    void contextLoads() throws MessagingException {

        List list = goodsMapper.selectList(null);

        list.forEach(System.out::println);

    }

}

2. 注解

只记录个人常用的

(1)@TableName

  • 描述:表名注解,用于实体类上,标识实体类对应的表
@TableName("sys_user")
public class User {
    private Long id;
    private String name;
    private Integer age;
    private String email;
}

(2)@TableId

  • 描述:主键注解,用于主键属性上,用于主键相关设置
@TableName("sys_user")
public class User {
    @TableId
    private Long id;
    private String name;
    private Integer age;
    private String email;
}
属性 类型 必须指定 默认值 描述
value String “” 主键字段名
type Enum IdType.NONE 指定主键类型

IdType

描述
AUTO 数据库 ID 自增
NONE 无状态,该类型为未设置主键类型(注解里等于跟随全局,全局里约等于 INPUT)
INPUT 自己注册自动填充插件进行填充
ASSIGN_ID 分配 ID(主键类型为 Number(Long 和 Integer)或 String)(since 3.3.0),使用接口IdentifierGenerator的方法nextId(默认实现类为DefaultIdentifierGenerator雪花算法)

(3)@Version

  • 注意:@Version自动更新,仅支持updateById(id)update(entity, wrapper) 方法

  • 描述:版本注解,用于实体类版本属性上,在数据更新时,实体类版本字段值自动更新

  • 实体类版本字段支持的类型:int,Integer,long,Long,Date,Timestamp,LocalDateTime

    • 整数类型下 newVersion = oldVersion + 1
    • 时间类型下,更新为当前时间

(4)@TableLogic

  • 描述:逻辑删除注解,用于实体类逻辑删除属性上,用于设置逻辑删除值
属性 类型 必须指定 默认值 描述
value String “”,默认值为0 逻辑未删除值
delval String “”,默认值为1 逻辑删除值

3. CRUD接口

说明:

Wrapper对象:条件构造器,用于封装SQL条件,支持链式编程;详情(官方文档)

泛型T:为任意实体对象

泛型E:为任意Mapper对象

Serializable参数:为任意类型主键

IPage接口:为分页接口,其实现类为Page

Page类:为分页实现类,封装有本页的size,record数据,totalcurrent当前页数等

Batch单词:批量处理

(1)Mapper CRUD接口

  • 说明:提供BaseMapper接口,内提供许多通用CRUD操作方法,由Mapper接口extends继承便可使用
  • BaseMapper公共方法前缀:select,update,delete,insert

分页相关方法

  • 说明:BaseMapper实现有与分页查询相关的方法
<!-- 相关方法 -->
// 根据 entity 条件,查询全部记录(并翻页)
IPage<T> selectPage(IPage<T> page, @Param(Constants.WRAPPER) Wrapper<T> queryWrapper);
// 根据 Wrapper 条件,查询全部记录(并翻页)
IPage<Map<String, Object>> selectMapsPage(IPage<T> page, @Param(Constants.WRAPPER) Wrapper<T> queryWrapper);


<!-- 示例 -->
EntityWrapper<Employee> ew = new EntityWrapper<Employee>();
List<Employee> result = employeeMapper.selectPage(new Page<>(1, 2),
          ew.between("id",1,20).eq("gender","F"));

(2)Service CRUD接口

  • 说明:提供ServiceImpl类,是对CRUD操作的进一步封装的,由pojo的ServiceImpl类extends继承。同时提供IService接口,是ServiceImpl的基类,由pojo的Service接口接口继承。
  • ServiceImpl公共方法前缀get,update,save

示例

<!-- goods服务接口-->
public interface GoodsService extends IService<Goods> {

}

<!-- goods服务实现类-->
@Service
public class GoodsServiceImpl extends ServiceImpl<GoodsMapper, Goods>
    implements GoodsService{

}

(3)ActiveRecord模式

  • 注意:实体类的mapper类要继承BaseMapper

  • 活性记录模式:让pojo对象活化,可自己进行数据持久化操作(说白了,就是让pojo继承许多CRUD操作方法。从而让pojo对象可以自己持久化自己)

  • 说明:提供Model类,内提供部分CRUD操作方法,由POJO类继承便可使用

4. 逻辑删除

  • 说明:对于配置了逻辑删除的实体类;select查找和update更新,追加where条件,过滤已逻辑删除的元素;delete删除,改为update操作,修改逻辑删除字段的值;insert插入,不做任何修改
    注意:以上CURD操作的追加和修改仅对自动注入的Sql起效(即自己在xml关系映射文件编写的sql不会被追加条件或修改操作)
  • insert问题:因为insert操作不会给逻辑删除字段自动赋予初值,所以需要我们自己设值
    • 方式一:字段在数据库定义默认值(推荐)
    • 方式二:insert前自己set值
    • 方式三:使用自动填充功能

应用

1)方式一

  • 说明:在application.yaml中配置
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
private Integer deleted;

5. 通用枚举

  • 说明:对于CRUD操作通用枚举属性,mybatisplus将枚举属性中标记属性的值,存于数据库(或赋予pojo属性)
    注意:以上CURD操作来自自动注入的Sql(即自己在xml关系映射文件编写的sql不行)

  • 通用枚举序列化问题:

应用

1)通用枚举定义

import lombok.Getter;

@Getter
public enum GenderEnum  {
    MALE("0","男"),
    FEMALE("1","女");

    GenderEnum(String value, String desc) {
        this.value = value;
        this.desc = desc;
    }
    @EnumValue
    private  final  String value;
    private final String desc;
}

2)配置

mybatis-plus:
# 通用枚举包扫描
  type-enums-package: com/springbootproject/enum

3)实体类使用

public class User {
    /**
     * 名字
     * 数据库字段: name varchar(20)
     */
    private String name;

    /**
     * 年龄,IEnum接口的枚举处理
     * 数据库字段:sex INT(1)
     */
    private GenderEnum sex;



6. 自动填充功能

  • 说明:基于处理器实现,用于对插入/更新操作进行数据填充

应用

1)标记填充字段

public class User {

    // 注意!这里需要标记为填充字段
    /**
    * FieldFill.DEFAULT 默认不处理
    * FieldFill.INSERT 插入时填充字段
    * FieldFill.UPDATE 更新时填充字段
    * FieldFill.INSERT_UPDATE 插入和更新时填充字段
    **/
    @TableField(.. fill = FieldFill.INSERT)
    private String fillField;

    ....
}



2)处理器

@Slf4j
@Component
public class MyMetaObjectHandler implements MetaObjectHandler {

    @Override
    public void insertFill(MetaObject metaObject) {
        log.info("start insert fill ....");
        this.strictInsertFill(metaObject, "createTime", LocalDateTime.class, LocalDateTime.now()); // 起始版本 3.3.0(推荐使用)
        // 或者
        this.strictInsertFill(metaObject, "createTime", () -> LocalDateTime.now(), LocalDateTime.class); // 起始版本 3.3.3(推荐)
        // 或者
        this.fillStrategy(metaObject, "createTime", LocalDateTime.now()); // 也可以使用(3.3.0 该方法有bug)
    }

    @Override
    public void updateFill(MetaObject metaObject) {
        log.info("start update fill ....");
        this.strictUpdateFill(metaObject, "updateTime", LocalDateTime.class, LocalDateTime.now()); // 起始版本 3.3.0(推荐)
        // 或者
        this.strictUpdateFill(metaObject, "updateTime", () -> LocalDateTime.now(), LocalDateTime.class); // 起始版本 3.3.3(推荐)
        // 或者
        this.fillStrategy(metaObject, "updateTime", LocalDateTime.now()); // 也可以使用(3.3.0 该方法有bug)
    }
}

7. 乐观锁插件

说明

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

悲观锁:与乐观锁相反

当项目并发更新时,存在对同一数据进行更新;

乐观锁方式:A线程条件更新执行到一半被B线程抢占,先更新了该数据,导致A线程条件更新的条件不满足了,那么A线程更新操作直接失败

悲观锁方式:A线程更新会对该数据上锁,更新完才解锁

乐观锁实现

version:是数据表中一个被加上@version注解的记录数据当前版本的字段

  • 乐观锁实现方式:
    • 取出记录时,获取当前 version
    • 更新时,带上这个 version
    • 执行更新时, 追加Where条件set version = newVersion where version = oldVersion
    • 如果 version 不对,就更新失败

1)标记版本字段

@Version
private Integer version;

2)乐观锁拦截器配置

注意:因@Version注解,仅支持 updateById(id)update(entity, wrapper) 方法。所以拦截器也只能使用

// Spring Boot 方式
@Configuration
@MapperScan("按需修改")  // 扫描需要配置乐观锁的pojo的mapper,根本作用是给扫描到的mapper的更新操作追加版本判断where条件;
public class MybatisPlusConfig {
    /**
     * 旧版
     */
    @Bean
    public OptimisticLockerInterceptor optimisticLockerInterceptor() {
        return new OptimisticLockerInterceptor();
    }

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

3)测试

@Test
public void test10(){
    User user1 = userMapper.selectById(1);
    user1.setUsername("kk");
    user1.setAddress("address1");

    // 抢占更新
    User user2 = userMapper.selectById(1);
    user2.setUsername("Mike");
    user2.setAddress("address2");
    userMapper.updateById(user2);

    // 根据返回的结果判断是否更新成功; 0:失败,1:成功
    int result =  userMapper.updateById(user1);
    if (result == 0){
        // 重新获取,更新
        user1 = userMapper.selectById(1);
        user1.setUsername("kk");
        user1.setAddress("address1");
        userMapper.updateById(user1);
    }

}

8. 其他

(1)雪花算法

雪花算法是Twitter开源的分布式ID生成算法.

主要是由64bit的long型生成的全局ID,引入了时间戳和ID保持自增的属性.

64bit分为四个部分:
第一个部分是1bit, 这不 使用,没有意义;
第二个部分是41bit, 组成时间戳;
第三个部分是10bit, 工作机器ID,里面分为两个部分,5个bit是的是机房号,代表最多有25即32个机房,5个bit是指机器的ID,代表最多有25个机器,即32个机器 .
第四部分是12bit, 代表是同一个毫秒类产生不同的ID,区分同一个毫秒内产生的ID.

总的来说就是一个机房,一台机器,在同一号毫秒时产生的ID,可能在同一秒钟产生不同的ID,最后12bit序列号可以区分在同一秒钟的不同ID.

你可能感兴趣的:(Java,mybatis,mysql,数据库)