逻辑删除根据官方配置就行,重点是配置后的支持物理删除
import cn.dev33.satoken.stp.StpUtil;
import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.override.MybatisMapperProxy;
import com.baomidou.mybatisplus.core.toolkit.MybatisUtils;
import com.baomidou.mybatisplus.extension.toolkit.SqlHelper;
import org.apache.ibatis.session.SqlSession;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.time.LocalDateTime;
import java.util.Optional;
/**
* 自定义BaseMapper
* 这里不会打印日志,可以在 service 中进行处理
*/
public interface MyBaseMapper<Entity> extends BaseMapper<Entity> {
/**
* 根据ID逻辑删除
*
* @param id 主键ID
* @return 是否删除成功
*/
default boolean deleteLogicById(Integer id) {
// 使用 UpdateWrapper 构建更新条件
UpdateWrapper<Entity> updateWrapper = new UpdateWrapper<>();
updateWrapper.eq("id", id)
.set("is_deleted", 1)
.set("deleted_by", Optional.of(StpUtil.getLoginIdAsInt()).orElse(0))
.set("deleted_at", LocalDateTime.now());
// 直接更新
return SqlHelper.retBool(this.update(updateWrapper));
}
/**
* 根据ID物理删除
*
* @param id 主键ID
* @return 是否删除成功
*/
default boolean deletePhysicalById(Integer id) {
try {
// 获取当前SqlSession和Mapper信息
MybatisMapperProxy<?> mybatisMapperProxy = MybatisUtils.getMybatisMapperProxy(this);
SqlSession sqlSession = mybatisMapperProxy.getSqlSession();
// 获取实体类型和表名
String tableName = getTableName();
// 构建物理删除SQL
String sql = "DELETE FROM " + tableName + " WHERE id = ?";
// 直接获取JDBC连接,完全绕过MyBatis拦截器
java.sql.Connection connection = sqlSession.getConnection();
try (java.sql.PreparedStatement ps = connection.prepareStatement(sql)) {
ps.setInt(1, id);
int rows = ps.executeUpdate();
return rows > 0;
}
} catch (Exception e) {
throw new RuntimeException("物理删除失败", e);
}
}
/**
* 获取当前Mapper对应实体的表名
*
* @return 表名
*/
@SuppressWarnings("unchecked")
default String getTableName() {
try {
// 获取当前Mapper接口
MybatisMapperProxy<?> mybatisMapperProxy = MybatisUtils.getMybatisMapperProxy(this);
Class<?> mapperInterface = mybatisMapperProxy.getMapperInterface();
// 查找泛型类型参数T
Type[] genericInterfaces = mapperInterface.getGenericInterfaces();
for (Type genericInterface : genericInterfaces) {
if (genericInterface instanceof ParameterizedType) {
ParameterizedType parameterizedType = (ParameterizedType) genericInterface;
if (parameterizedType.getRawType() == MyBaseMapper.class
|| parameterizedType.getRawType() == BaseMapper.class) {
Type[] typeArguments = parameterizedType.getActualTypeArguments();
if (typeArguments.length > 0 && typeArguments[0] instanceof Class) {
Class<?> entityClass = (Class<?>) typeArguments[0];
// 只从@TableName注解获取表名
if (entityClass.isAnnotationPresent(TableName.class)) {
return entityClass.getAnnotation(TableName.class).value();
}
// 如果没有注解,报错
throw new RuntimeException(
"实体类 " + entityClass.getName() + " 没有 @TableName 注解,无法获取表名");
}
}
}
}
throw new RuntimeException("无法确定实体类对应的表名,请在实体类上添加 @TableName 注解");
} catch (Exception e) {
throw new RuntimeException("获取表名失败: " + e.getMessage(), e);
}
}
/**
* 获取泛型类型T
*
* @return 实体类类型
*/
@SuppressWarnings("unchecked")
default Class<Entity> getEntityClass() {
Type genericInterface = this.getClass().getGenericInterfaces()[0];
if (genericInterface instanceof ParameterizedType) {
Type[] typeArguments = ((ParameterizedType) genericInterface).getActualTypeArguments();
return (Class<Entity>) typeArguments[0];
}
// 尝试从接口定义获取
Type mapperInterfaceType = getClass().getInterfaces()[0].getGenericInterfaces()[0];
if (mapperInterfaceType instanceof ParameterizedType) {
Type[] typeArguments = ((ParameterizedType) mapperInterfaceType).getActualTypeArguments();
return (Class<Entity>) typeArguments[0];
}
throw new RuntimeException("无法获取实体类型");
}
}