常见需求
逻辑删除
- 插入: 不作限制
- 查找: 追加where条件过滤掉已删除数据,且使用
wrapper.entity
生成的where条件会忽略该字段 - 更新: 追加where条件防止更新到已删除数据,且使用
wrapper.entity
生成的where条件会忽略该字段 - 删除: 转变为更新
注意事项
- 自定义SQL不会添加逻辑删除功能,可通过自己在SQL中添加该条件或在Wrapper中添加该条件来解决
- 在查询时,也会默认查询出删除标记字段,可通过实体上的该标记属性添加
@TableField(select = false)
注解来解决
- 添加逻辑删除配置
mybatis-plus:
global-config:
db-config:
logic-delete-field: deleted # 全局逻辑删除的实体字段名
logic-delete-value: 1 # 逻辑已删除值(默认为 1)
logic-not-delete-value: 0 # 逻辑未删除值(默认为 0)
- 如果是3.1.1之前版本,需要在配置类中注册sql注入器
@Configuration
public class MybatisPlusConfig {
@Bean
public ISqlInjector SqlInjector() {
return new LogicSqlInjector();
}
}
- 如果是3.3.0之前版本,需要在实体类的删除标记字段上,加上
@TableLogic
注解
@TableLogic
private Integer deleted;
自动填充
- 使用
@TableField
注解,修改注解的fill
属性为FieldFill
枚举类的属性
枚举类型 | 描述 |
---|---|
DEFAULT |
默认不处理 |
INSERT |
插入填充字段 |
UPDATE |
更新填充字段 |
INSERT_UPDATE |
插入和更新填充字段 |
- 定义处理器类,实现MyMetaObjectHandler接口
@Component
public class MyMetaObjectHandler implements MetaObjectHandler {
@Override
public void insertFill(MetaObject metaObject) { //插入填充
String fieldName = "createTime";
if (!metaObject.hasSetter(fieldName)) { //如果该实体没有要填充的字段则跳过
return;
}
if (this.getFieldValByName(fieldName,metaObject) != null) { //如果实体实体已经自定义了该字段的值则跳过
return;
}
this.setFieldValByName(fieldName, LocalDateTime.now(), metaObject); //参数依次是:要填充的字段名、要填充的内容、元数据对象
}
@Override
public void updateFill(MetaObject metaObject) { //更新填充
String fieldName = "updateTime";
if (!metaObject.hasSetter(fieldName)) { //如果该实体没有要填充的字段则跳过
return;
}
if (this.getFieldValByName(fieldName,metaObject) != null) { //如果实体实体已经自定义了该字段的值则跳过
return;
}
this.setFieldValByName(fieldName, LocalDateTime.now(), metaObject); //参数依次是:要填充的字段名、要填充的内容、元数据对象
}
}
乐观锁
注意事项
- 支持的数据类型只有:int,Integer,long,Long,Date,Timestamp,LocalDateTime
- 整数类型下
newVersion = oldVersion + 1
,并且会回写到entity
中- 仅支持
updateById(id)
与update(entity, wrapper)
方法,并且在update(entity, wrapper)
方法下,wrapper
不能复用,否则插件会拼接两个version条件字段
- 配置乐观锁插件
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor(); //创建MybatisPlus拦截器
interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor()); //添加乐观锁插件
return interceptor;
}
- 在实体类的version字段上加上
@Version
注解
@Version
private Integer version;
性能分析
- 将下面的依赖代码加入pom.xml文件中
<dependency>
<groupId>p6spy</groupId>
<artifactId>p6spy</artifactId>
<version>x.x.x</version>
</dependency>
- 将application配置文件中数据库驱动和数据库连接URL修改为p6spy的格式
spring.datasource.driverClassName=com.p6spy.engine.spy.P6SpyDriver
spring.datasource.url=jdbc:p6spy:mysql://IP地址:端口/数据库?参数
- 在application配置文件同级目录下创建
spy.properties
文件,进行下面配置
# 指定应用的日志拦截模块,默认为com.p6spy.engine.spy.P6SpyFactory
#3.2.1以上使用
modulelist=com.baomidou.mybatisplus.extension.p6spy.MybatisPlusLogFactory,com.p6spy.engine.outage.P6OutageFactory
#3.2.1以下使用或者不配置
#modulelist=com.p6spy.engine.logging.P6LogFactory,com.p6spy.engine.outage.P6OutageFactory
# 真实JDBC driver , 多个以 逗号 分割 默认为空
driverlist=com.mysql.cj.jdbc.Driver
# 配置SimpleDateFormat日期格式 默认为空
dateformat=yyyy-MM-dd HH:mm:ss
# 控制台打印
appender=com.p6spy.engine.spy.appender.StdoutLogger
# 日志系统打印
#appender=com.p6spy.engine.spy.appender.Slf4JLogger
# 文件打印
#appender=com.p6spy.engine.spy.appender.FileLogger
# 指定 Log 的文件名 默认 spy.log
#logfile=spy.log
# 指定是否每次是增加 Log,设置为 false 则每次都会先进行清空 默认true
#append=true
# 指定日志输出样式 默认为com.p6spy.engine.spy.appender.SingleLineFormat , 单行输出 不格式化语句
logMessageFormat=com.baomidou.mybatisplus.extension.p6spy.P6SpyLogger
# 也可以采用 com.p6spy.engine.spy.appender.CustomLineFormat 来自定义输出样式, 默认值是%(currentTime)|%(executionTime)|%(category)|connection%(connectionId)|%(sqlSingleLine)
# 可用的变量为:
# %(connectionId) connection id
# %(currentTime) 当前时间
# %(executionTime) 执行耗时
# %(category) 执行分组
# %(effectiveSql) 提交的SQL 换行
# %(effectiveSqlSingleLine) 提交的SQL 不换行显示
# %(sql) 执行的真实SQL语句,已替换占位
# %(sqlSingleLine) 执行的真实SQL语句,已替换占位 不换行显示
#customLogMessageFormat=%(currentTime)|%(executionTime)|%(category)|connection%(connectionId)|%(sqlSingleLine)
# 设置 p6spy driver 代理
deregisterdrivers=true
# 取消JDBC URL前缀
useprefix=true
# date类型字段记录日志时使用的日期格式 默认dd-MMM-yy
databaseDialectDateFormat=dd-MMM-yy
# boolean类型字段记录日志时使用的日期格式 默认boolean 可选值numeric
databaseDialectBooleanFormat=boolean
#显示指定过滤 Log 时排队的分类列表,取值:
#error, info, batch, debug, statement, commit, rollback, result and resultset are valid values
#(默认 info,debug,result,resultset,batch)
excludecategories=info,debug,result,resultset,batch
# P6Outage 模块是否记录较长时间运行的语句 默认false
outagedetection=true
# P6Outage 模块执行时间设置,整数值 (以秒为单位)),只有当超过这个时间才进行记录 Log。 默认30s
outagedetectioninterval=2
动态表名
- 配置动态表名插件
@Configuration
public class MybatisPlusConfig {
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor(); //创建MybatisPlus拦截器
DynamicTableNameInnerInterceptor dynamicTableNameInnerInterceptor = new DynamicTableNameInnerInterceptor(); //创建动态表名解析器
HashMap<String, TableNameHandler> map = new HashMap<>(); //用于存储表名和表名处理器的映射关系
map.put("user", (sql, tableName) -> { //这里的表名是数据库中的表名而并非实体名
String suffix = "_01";
//此处可对表后缀增加一些逻辑
return tableName + suffix; //原来表名拼接一个经过逻辑处理后的后缀,如果返回null则不替换
});
dynamicTableNameInnerInterceptor.setTableNameHandlerMap(map); //将表名和动态表名映射关系设置
interceptor.addInnerInterceptor(dynamicTableNameInnerInterceptor); //添加动态表名解析器
return interceptor;
}
}
- 之后在对原表名进行处理时,会先对表名进行动态处理,之后才会执行SQL语句
代码生成器
- 引入代码生成器依赖和模版引擎依赖
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-generator</artifactId>
<version>x.x.x</version>
</dependency>
<dependency>
<groupId>org.freemarker</groupId>
<artifactId>freemarker</artifactId>
<version>x.x.x</version>
</dependency>
- 编写代码,配置代码生成器
class CodeGenerator {
public static String scanner(String tip) {
Scanner scanner = new Scanner(System.in);
StringBuilder help = new StringBuilder();
help.append("请输入" + tip + ":");
System.out.println(help.toString());
if (scanner.hasNext()) {
String ipt = scanner.next();
if (StringUtils.isNotBlank(ipt)) {
return ipt;
}
}
throw new MybatisPlusException("请输入正确的" + tip + "!");
}
public static void main(String[] args) {
// 代码生成器
AutoGenerator autoGenerator = new AutoGenerator();
// 全局配置
GlobalConfig globalConfig = new GlobalConfig();
String projectPath = System.getProperty("user.dir"); //当前运行路径
globalConfig.setOutputDir(projectPath + "/src/main/java"); //输出目录
globalConfig.setAuthor("作者"); //作者
globalConfig.setOpen(false); //生成完后是否打开资源管理器
globalConfig.setServiceName("%sService"); //去掉Service杰昆的首字母I
globalConfig.setFileOverride(false); //重新生死文件时文件是否覆盖
globalConfig.setIdType(IdType.ASSIGN_ID); //主键生成策略
globalConfig.setDateType(DateType.ONLY_DATE); //定义生成实体类中的日期类型
globalConfig.setSwagger2(true); //实体属性使用Swagger2注解
autoGenerator.setGlobalConfig(globalConfig);
// 数据源配置
DataSourceConfig dataSourceConfig = new DataSourceConfig();
dataSourceConfig.setDbType(DbType.MYSQL);
dataSourceConfig.setUrl("jdbc:mysql://localhost:3306/ant?useUnicode=true&useSSL=false&characterEncoding=utf8");
dataSourceConfig.setSchemaName("public");
dataSourceConfig.setDriverName("com.mysql.cj.jdbc.Driver");
dataSourceConfig.setUsername("root");
dataSourceConfig.setPassword("密码");
autoGenerator.setDataSource(dataSourceConfig);
// 包配置
PackageConfig packageConfig = new PackageConfig();
packageConfig.setParent(scanner("父包名")); //父包名
packageConfig.setModuleName(scanner("当前模块名")); //当前模块名
packageConfig.setController("controller");
packageConfig.setEntity("entity");
packageConfig.setService("service");
packageConfig.setMapper("mapper");
autoGenerator.setPackageInfo(packageConfig);
// 模版引擎配置
autoGenerator.setTemplateEngine(new FreemarkerTemplateEngine());
// 策略配置
StrategyConfig strategyConfig = new StrategyConfig();
strategyConfig.setNaming(NamingStrategy.underline_to_camel); //数据库表名映射到实体的命名策略
strategyConfig.setColumnNaming(NamingStrategy.underline_to_camel); //数据库表列名映射到实体的命名策略
strategyConfig.setRestControllerStyle(true); //restful api风格控制器
strategyConfig.setEntityLombokModel(true); // lombok 模型 @Accessors(chain = true) setter链式操作
//strategyConfig.setSuperControllerClass("你自己的父类控制器,没有就不用设置!");
//strategyConfig.setSuperEntityClass("你自己的父类实体,没有就不用设置!");
strategyConfig.setInclude(scanner("表名,多个英文逗号分割").split(","));
strategyConfig.setControllerMappingHyphenStyle(true); //url中驼峰转连字符
strategyConfig.setTablePrefix(packageConfig.getModuleName() + "_"); //生成实体时去掉表前缀
autoGenerator.setStrategy(strategyConfig);
autoGenerator.execute();
System.exit(0);
}
}
Comments NOTHING