一、关于MyBatisPlus的逻辑删除
如果我们使用MyBatisPlus作为ORM框架,可以很方便地使用其提供的逻辑删除功能。在实体类上使用@TableLogic注解即可开启逻辑删除功能,其默认为0为未删除状态,1为已删除状态。例如:
@Data
@TableName("user")
public class User {
@TableId(type = IdType.AUTO)
private Long id;
private String name;
private Integer age;
@TableLogic
private Integer deleted;
}
在进行查询时,MyBatisPlus会自动过滤已被删除的数据,从而实现逻辑删除的效果。
但是,在某些情况下,使用逻辑删除只是隐形地屏蔽了已删除的数据,而从数据库中彻底删除这些数据可能会更加合适。下面介绍一种解决方案。
二、解决方案:自定义MyBatisPlus全局配置
- 创建 MybatisPlusConfig 类,继承 GlobalConfig 类,并在其中实现自定义全局配置(例如逻辑删除实现完全删除)
@Configuration
public class MybatisPlusConfig {
@Bean
public GlobalConfig globalConfig() {
GlobalConfig globalConfig = new GlobalConfig();
// 逻辑删除配置
globalConfig.setMetaObjectHandler(new MyMetaObjectHandler());
return globalConfig;
}
// MyMetaObjectHandler 类中实现完全删除的逻辑
}
- 修改 application.yml 文件,加入设置
mybatis-plus:
global-config:
db-config:
logic-delete-value: 1
logic-not-delete-value: 0
- 实现逻辑删除为完全删除的 MyMetaObjectHandler 类
public class MyMetaObjectHandler implements MetaObjectHandler {
@Override
public void insertFill(MetaObject metaObject) {
Object fieldValue = getFieldValByName("delete_flag", metaObject);
if (fieldValue == null) {
setFieldValByName("delete_flag", 0, metaObject);
}
}
@Override
public void updateFill(MetaObject metaObject) {
}
}
MyMetaObjectHandler 类中,我们重写了 insertFill 方法,在插入数据时,默认为 delete_flag 字段设置未删除状态,即0。
- 创建实体类
@Data
@TableName("user")
public class User {
@TableId(type = IdType.AUTO)
private Long id;
private String name;
private Integer age;
@TableField("delete_flag")
private Integer deleteFlag; // 用于完全删除的字段
}
- 使用示例
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {
@Override
public boolean removeById(Serializable id) {
User user = new User();
user.setId((Long)id);
return this.baseMapper.delete(user) > 0;
}
}
在使用 removeById 方法时,我们通过创建一个新的 User 对象,将其 id 设置为需要删除的 id,然后使用 MyBatisPlus 提供的 delete 方法,实现完全删除的效果。
三、关于MyBatisPlus的唯一索引
在MyBatisPlus中,我们可以使用@Index注解实现索引。例如:
@Data
@TableName("user")
public class User {
@TableId(type = IdType.AUTO)
private Long id;
private String name;
private Integer age;
@Index(unique = true)
private String email;
}
在这里,我们给 email 字段设置了唯一索引。如果我们在插入数据时违反了唯一索引的限制,MyBatisPlus 会抛出 DuplicateKeyException 异常。
但是,MyBatisPlus 并没有提供专门处理这种异常的机制。下面介绍一种解决方案。
四、解决方案:自定义异常处理器
- 创建 CustomSQLExceptionHandler 类,继承 DefaultSQLExceptionHandler 继承处理器类,并在其中实现异常处理逻辑
public class CustomSQLExceptionHandler extends DefaultSQLExceptionHandler {
@Override
public void handler(String sql, SQLException e) {
// 判断异常类型
if (e.getErrorCode() == 1062) {
// 获取唯一索引的名称
String indexName = e.getMessage().split("'")[1];
String message = String.format("字段 %s 违反唯一性约束:%s", indexName.replaceAll("_unique", ""), e.getMessage());
throw new CustomException(message);
}
// 调用父类的 handler 方法,处理其他类型的异常
super.handler(sql, e);
}
}
在 CustomSQLExceptionHandler 中,我们重写了 handler 方法,在 catch 到 DuplicateKeyException 异常后,通过异常类中的 getMessage 方法获取唯一索引的名称,然后构造具有更加信息化的异常消息,并将其抛出。
- 在 MybatisPlusConfig 类中,设置 GlobalConfig 的 sqlExceptionTranslator 属性为 CustomSQLExceptionHandler
@Configuration
public class MybatisPlusConfig {
@Bean
public GlobalConfig globalConfig() {
GlobalConfig globalConfig = new GlobalConfig();
globalConfig.setSqlExceptionTranslator(new CustomSQLExceptionHandler());
return globalConfig;
}
}
在这里,我们创建了一个自定义的 sqlExceptionTranslator,用 CustomSQLExceptionHandler 来处理 SQL 异常。
- 创建 CustomException 异常类,用于封装自定义异常消息
public class CustomException extends RuntimeException {
public CustomException(String message) {
super(message);
}
}
- 使用示例
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {
@Override
public void addUser(User user) {
if (this.baseMapper.insert(user) == 0) {
throw new CustomException("用户添加失败");
}
}
}
在 addUser 方法中,我们在插入数据时进行唯一性检查。如果违反了唯一索引的约束条件,CustomSQLExceptionHandler 会抛出自定义的异常 CustomException,提示用户出现了重复数据。
以上就是解析MyBatisPlus解决逻辑删除与唯一索引的兼容问题的完整攻略,希望能够对你有所帮助。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:解析MyBatisPlus解决逻辑删除与唯一索引的兼容问题 - Python技术站