一、分页
- 配置MybatisPlusInterceptor拦截器,添加分页功能
@Configuration public class MybatisPlusConfig { @Bean public MybatisPlusInterceptor mybatisPlusInterceptor() { //利用MybatisPlus提供的分页 MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor(); mybatisPlusInterceptor.addInnerInterceptor(new PaginationInnerInterceptor()); return mybatisPlusInterceptor; } }
- 利用IPage的实现类Page实现分页
Page<Entity> pageInfo = new Page<>(page, pageSize); entityService.page(pageInfo, queryWrapper); //利用page方法根据pageInfo和传入的条件进行分页
- 原理分析
首先讲分页参数PageNum、PageSize放到ThreadLocal中,拦截执行的SQL,根据数据库类型(如默认为MySql)添加对应的分页语句重写SQL。在分页中主要是先计算count(*)总个数,以及添加limit分页查询,进而得出total总条数、当前页的数据,是否为首页,总页数等信息。
二、映射匹配
-
@TableField
:解决数据库表和实体类字段不匹配
(1)value属性:设置与实体类属性对应的数据库表字段名称。
(2)exist属性:设置实体类属性在对应的数据库表字段中是否存在,默认为true,无法与value合并使用。
(3)select属性:设置实体类属性是否参与查询,默认为true,适用于对密码等核心信息的隐藏(若登录时要验证密码,可以使用查询投影,即使用LambdaQueryWrapper的select方法指定要查询的字段)。
(4)fill属性:使用方法 fill = FieldFill.UPDATE
(1) 创建工具类,由于客户端发送的每次HTTP请求,在服务器中都会分配一个线程来处理,因此只需在拦截器里设置id到一个ThreadLocal中,就可以在Controller和MyMetaObjectHandler从中取出对应的值,它们都是处于一个线程中。 public class BaseContextUtils { private static ThreadLocal<Long> threadLocal = new ThreadLocal<>(); public static void setCurrentId(Long id) { threadLocal.set(id); } public static Long getCurrentId() { return threadLocal.get(); } } (2) 自定义MetaObjectHandler接口的实现类,重写update和insert后填充的字段 @Component public class MyMetaObjectHandler implements MetaObjectHandler { @Override public void insertFill(MetaObject metaObject) { metaObject.setValue("createTime", LocalDateTime.now()); metaObject.setValue("updateTime", LocalDateTime.now()); metaObject.setValue("createUser", BaseContextUtils.getCurrentId()); metaObject.setValue("updateUser", BaseContextUtils.getCurrentId()); } @Override public void updateFill(MetaObject metaObject) { metaObject.setValue("updateTime", LocalDateTime.now()); metaObject.setValue("updateUser", BaseContextUtils.getCurrentId()); } }
-
@TableName
:设置与实体类名对应的数据库表名
三、ID生成策略
@TableId
:设置当前实体类中主键属性的生成策略
(1)value属性:设置与实体类主键属性对应的数据库表的主键名称。
(2)type属性:设置主键属性的生成策略:
IdType.AUTO:数据库ID自增,即AUTO_INCREMENT(使用时要开启表的自动递增)
IdType.NONE:没有设置ID生成策略
IdType.INPUT:用户输入ID
IdType.ASSIGN_ID
:雪花算法生成ID,兼容主键是数值型与字符串型(只有当插入对象ID为空,才自动填充,下同)
IdType.ASSIGN_UUID
:UUID算法生成ID(不包含-)- 全局配置:
mybatis-plus: configuration: map-underscore-to-camel-case: true # 开启数据库表字段下划线连接与实体类驼峰之间的映射 log-impl: org.apache.ibatis.logging.stdout.StdOutImpl # 在控制台输出Mybatis-plus日志 global-config: db-config: id-type: ASSIGN_ID # 全局ID生成策略 table-prefix: tb_ # 全局表的公共前缀
四、逻辑删除
@TableLogic(value = "0", delval = "1")
:value指定逻辑删除字段存在时的默认值,delval指定逻辑删除后的默认值。(设置后,删除操作就编程了更新操作,查询操作都会指定逻辑删除字段为0)- 全局配置
mybatis-plus: global-config: db-config: logic-delete-field: deleted # 全局逻辑删除字段名 logic-not-delete-value: 0 # 全局没有逻辑删除时默认值 logic-delete-value: 1 # 全局逻辑删除后默认值
五、乐观锁
先查询出要修改的数据,并获取对应的version,执行修改操作,谁先抢到就会先执行修改操作,同时会将version自增1,这样后抢到的就会因为version不一致而无法修改。本质就是动态添加了set version = version+1 where version=value
- 在数据库表中添加整型字段version
- 在实体类上version属性上添加
@Version
注解 - 在MybatisPlusInterceptor拦截器配置中添加乐观锁拦截器:
mybatisPlusInterceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
六、代码生成器
- 导入依赖MybatisPlus官网代码生成器
<!-- MyBatisPlus代码生成器 --> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-generator</artifactId> <version>3.5.3.1</version> </dependency> <!-- Velocity模板引擎 --> <dependency> <groupId>org.apache.velocity</groupId> <artifactId>velocity-engine-core</artifactId> <version>2.3</version> </dependency> <!-- Freemarker模板引擎 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-freemarker</artifactId> <version>3.0.6</version> </dependency>
- 创建代码生成器类
public class MyFastAutoGenerator { public static void main(String[] args) { List<String> tables = new ArrayList<>(); //数据库表 tables.add("tb_user"); tables.add("tb_order"); List<IFill> tableFillList = new ArrayList<>(); tableFillList.add(new Property("createTime", FieldFill.INSERT)); tableFillList.add(new Property("createUser", FieldFill.INSERT)); tableFillList.add(new Property("updateTime", FieldFill.INSERT_UPDATE)); tableFillList.add(new Property("updateUser", FieldFill.INSERT_UPDATE)); FastAutoGenerator.create("jdbc:mysql://localhost:3306/test?serverTimezone=UTC", "root", "123456") .globalConfig(builder -> { builder.author("superm`超") // 设置作者 .enableSwagger() // 开启swagger模式 .outputDir(System.getProperty("user.dir") + "\\src\\main\\java"); // 指定输出目录 }) .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.superm") // 设置父包名 .moduleName("practice") // 设置父包模块名 .pathInfo(Collections.singletonMap(OutputFile.xml, System.getProperty("user.dir") + "\\src\\main\\resources\\mapper")); // 设置mapperXml生成路径 }) .strategyConfig(builder -> { builder.addInclude(tables) // 设置需要生成的表名 .addTablePrefix("tb_") // 设置过滤表前缀 .entityBuilder() //配置实体类 .enableLombok() //开启Lombok .logicDeleteColumnName("deleted") //说明逻辑删除的字段 .idType(IdType.ASSIGN_ID) //指定主键ID生成类型 .addTableFills(tableFillList) //添加填充字段 .controllerBuilder() //配置Controller .enableRestStyle() //开启RestController .enableFileOverride(); //覆盖已生成文件 }) .templateEngine(new FreemarkerTemplateEngine()) // 使用Freemarker引擎模板,默认的是Velocity引擎模板 .execute(); } }