mybatis-plus拦截器、字段填充器、类型处理器、表名替换、SqlInjector(联合主键处理)

mybatis-plus是一个优秀的ORM框架,除了提供一些常规的功能,还提供了一些高级功能,比如拦截器、字段填充器、类型处理器、表名替换、SqlInjector(联合主键处理)等,这些功能都可以方便我们进行业务开发,以下是详细讲解:

Mybatis-plus拦截器

Mybatis-plus提供了拦截器机制,使得我们可以对Sql语句进行拦截和修改,甚至可以在sql语句执行前后进行处理,这样可以实现一些高级功能,比如动态表名、分表、数据权限等。

接下来是一个通过Mybatis-plus拦截器实现动态表名的示例:

public class DynamicTableNameInterceptor implements Interceptor {

    /**
     * 根据规则构造新表名
     * @param name 原始表名
     * @param parameter sql执行参数
     * @param mapper sql执行Mapper对象
     * @return 返回新表名
     */
    @Override
    public String changeTableName(String name, Object parameter, MapperMethod mapper) {
        // 从执行参数中获取参数值
        Long userId = (Long) ReflectionUtils.invokeGetter(parameter, "userId");
        // 构造新表名
        String tableName = "user" + userId % 10;
        return tableName;
    }

    /**
     * 拦截器逻辑实现
     * @param invocation 拦截器调用方法
     * @return 返回执行结果
     * @throws Throwable 抛出异常
     */
    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        // 获取MappedStatement对象
        MappedStatement mappedStatement = (MappedStatement) invocation.getArgs()[0];
        // 获取sql参数
        Object parameter = invocation.getArgs()[1];
        // 获取MapperMethod对象
        MapperMethod mapper = (MapperMethod) invocation.getArgs()[2];
        // 获取原始表名
        String name = mappedStatement.getId().substring(mappedStatement.getId().lastIndexOf(".") + 1);
        // 获取新表名
        String tableName = changeTableName(name, parameter, mapper);
        // 替换表名
        SqlSource sqlSource = mappedStatement.getSqlSource();
        String sql = sqlSource.getBoundSql(parameter).getSql();
        sql = sql.replaceAll(name, tableName);
        BoundSql newBoundSql = new BoundSql(mappedStatement.getConfiguration(), sql, sqlSource.getBoundSql(parameter).getParameterMappings(), parameter);
        MappedStatement.Builder builder = new MappedStatement.Builder(mappedStatement.getConfiguration(), mappedStatement.getId(), new BoundSqlSqlSource(newBoundSql), mappedStatement.getSqlCommandType());
        builder.resource(mappedStatement.getResource());
        builder.fetchSize(mappedStatement.getFetchSize());
        builder.statementType(mappedStatement.getStatementType());
        builder.timeout(mappedStatement.getTimeout());
        builder.parameterMap(mappedStatement.getParameterMap());
        builder.resultMaps(mappedStatement.getResultMaps());
        builder.cache(mappedStatement.getCache());
        builder.flushCacheRequired(mappedStatement.isFlushCacheRequired());
        builder.useCache(mappedStatement.isUseCache());
        MappedStatement newMappedStatement = builder.build();
        invocation.getArgs()[0] = newMappedStatement;
        // 执行sql语句
        return invocation.proceed();
    }

    private static class BoundSqlSqlSource implements SqlSource {

        BoundSql boundSql;

        public BoundSqlSqlSource(BoundSql boundSql) {
            this.boundSql = boundSql;
        }

        @Override
        public BoundSql getBoundSql(Object parameterObject) {
            return boundSql;
        }
    }
}

Mybatis-plus字段填充器

Mybatis-plus提供了字段填充器,使得我们可以在插入或更新数据时自动填充某些字段,比如创建人、创建时间、更新人、更新时间等。

接下来是一个通过Mybatis-plus字段填充器实现创建时间和更新时间字段自动填充的示例:

@Component
public class MyMetaObjectHandler implements MetaObjectHandler {

    /**
     * 插入数据时填充创建时间和更新时间
     * @param metaObject MyMetaObjectHandler对象
     */
    @Override
    public void insertFill(MetaObject metaObject) {
        // 填充创建时间
        setValue("createTime", LocalDateTime.now(), metaObject);
        // 填充更新时间
        setValue("updateTime", LocalDateTime.now(), metaObject);
    }

    /**
     * 更新数据时填充更新时间
     * @param metaObject MyMetaObjectHandler对象
     */
    @Override
    public void updateFill(MetaObject metaObject) {
        // 填充更新时间
        setValue("updateTime", LocalDateTime.now(), metaObject);
    }

    /**
     * 设置字段值
     * @param fieldName 字段名称
     * @param value 字段值
     * @param metaObject MyMetaObjectHandler对象
     */
    private void setValue(String fieldName, Object value, MetaObject metaObject) {
        if (metaObject.hasSetter(fieldName)) {
            metaObject.setValue(fieldName, value);
        }
    }
}

Mybatis-plus类型处理器

Mybatis-plus提供了类型处理器,可以方便地将java类型转换为数据库类型,比如将Java的LocalDateTime类型转换为MYSQL的datetime类型。

接下来是一个通过Mybatis-plus类型处理器将LocalDataTime类型转成long类型的示例:

public class LocalDateTimeTypeHandler extends BaseTypeHandler<LocalDateTime> {

    /**
     * 将LocalDateTime类型转换为long类型保存到数据库中
     * @param preparedStatement PreparedStatement对象
     * @param i 参数下标
     * @param localDateTime LocalDateTime对象
     * @param jdbcType jdbc类型
     * @throws SQLException 执行异常
     */
    @Override
    public void setNonNullParameter(PreparedStatement preparedStatement, int i, LocalDateTime localDateTime, JdbcType jdbcType) throws SQLException {
        preparedStatement.setLong(i, localDateTime.toInstant(ZoneOffset.of("+8")).toEpochMilli());
    }

    /**
     * 将long类型转换为LocalDateTime类型返回
     * @param resultSet ResultSet对象
     * @param s 列名
     * @return 返回LocalDateTime对象
     * @throws SQLException 执行异常
     */
    @Override
    public LocalDateTime getNullableResult(ResultSet resultSet, String s) throws SQLException {
        long dateTimeStamp = resultSet.getLong(s);
        if (dateTimeStamp != 0) {
            return LocalDateTime.ofInstant(Instant.ofEpochMilli(dateTimeStamp), ZoneOffset.of("+8"));
        }
        return null;
    }

    /**
     * 将long类型转换为LocalDateTime类型返回
     * @param resultSet ResultSet对象
     * @param i 列的下标
     * @return 返回LocalDateTime对象
     * @throws SQLException 执行异常
     */
    @Override
    public LocalDateTime getNullableResult(ResultSet resultSet, int i) throws SQLException {
        long dateTimeStamp = resultSet.getLong(i);
        if (dateTimeStamp != 0) {
            return LocalDateTime.ofInstant(Instant.ofEpochMilli(dateTimeStamp), ZoneOffset.of("+8"));
        }
        return null;
    }

    /**
     * 将long类型转换为LocalDateTime类型返回
     * @param callableStatement CallableStatement对象
     * @param i 列的下标
     * @return 返回LocalDateTime对象
     * @throws SQLException 执行异常
     */
    @Override
    public LocalDateTime getNullableResult(CallableStatement callableStatement, int i) throws SQLException {
        long dateTimeStamp = callableStatement.getLong(i);
        if (dateTimeStamp != 0) {
            return LocalDateTime.ofInstant(Instant.ofEpochMilli(dateTimeStamp), ZoneOffset.of("+8"));
        }
        return null;
    }
}

Mybatis-plus表名替换

表名替换功能可以让我们在查询时将真实表名替换为其他名字,这样可以避免其他应用程序获取到真实的表名。

接下来是一个通过Mybatis-plus表名替换功能将真实表名替换为别名表名的示例:

public class TableNameHandler implements ITableNameHandler {

    /**
     * 替换表名为别名
     * @param tableName 表名
     * @param tablePojo 实体类型
     * @return 返回替换后的表名
     */
    @Override
    public String dynamicTableName(String tableName, Class<?> tablePojo) {
        if (User.class.isAssignableFrom(tablePojo)) {
            tableName = "user_alias";
        } else if (Order.class.isAssignableFrom(tablePojo)) {
            tableName = "order_alias";
        }
        return tableName;
    }
}

Mybatis-plus SqlInjector

SqlInjector实现类可以方便的扩展Mybatis-plus的业务,比如多表关联查询、联合主键处理等。

接下来是一个通过Mybatis-plus SqlInjector实现联合主键处理的示例:

public abstract class AbstractLogicDeleteByIdsWithFill<T> implements ISqlInjector {

    /**
     * 通过ID批量逻辑删除
     * @param tableMeta 逻辑删除表的表元信息
     * @param idList ID列表
     * @return 返回更新记录数
     */
    protected abstract Integer deleteByIdsWithFill(TableInfo tableMeta, Collection<? extends Serializable> idList);

    /**
     * 获取删除标记字段
     * @param tableMeta 表元信息
     * @return 返回逻辑删除字段名称
     */
    protected abstract String getLogicDeleteFieldName(TableInfo tableMeta);

    /**
     * 是否开启了多标签
     * @param globalConfig 全局配置
     * @param idSql 待执行的SQL
     * @return 返回是否开启了多标签
     */
    protected abstract boolean openMultiDelete(GlobalConfig globalConfig, String idSql);

    /**
     * 获取被逻辑删除的记录数
     * @param metaObject 元对象,可以获取到Mybatis-plus的参数对象
     * @return 返回记录数
     */
    protected abstract String getDeleteCount(MetaObject metaObject);


    @Override
    public void injectSqlRunner(SqlRunner sqlRunner) {
        GlobalConfig globalConfig = GlobalConfigUtils.getGlobalConfig(sqlRunner.getSqlSessionFactory());
        MetaObject metaObject = sqlRunner.getSqlObject().getMetaObject();
        TableInfo tableInfo = MetaUtils.getTableInfo(metaObject);
        String logicDeleteField = getLogicDeleteFieldName(tableInfo);
        // 获取所有ID
        List<Serializable> idList = getIdList(metaObject, tableInfo);
        if (idList.isEmpty()) {
            return;
        }
        // 更新被逻辑删除的记录数
        metaObject.setValue("deleteCount", getDeleteCount(metaObject));
        // 生成SQL
        String deleteSql = SqlHelper.logicDeleteSql(tableInfo, globalConfig.getLogicDeleteValue(logicDeleteField), globalConfig.getLogicNotDeleteValue(logicDeleteField), SqlHelper.getTableStructure(metaObject), idList);
        logger.debug("logic-delete-sql: {}", deleteSql);
        // 是否开启了多标签
        if (openMultiDelete(globalConfig, deleteSql)) {
            AtomicInteger results = new AtomicInteger(0);
            String[] idArray = idList.stream().map((id) -> "'" + id + "'").toArray(String[]::new);
            int batchSize = SqlExecutorConstants.BATCH_SIZE;
            for (int i = 0; i < idArray.length; i += batchSize) {
                StringBuilder sb = new StringBuilder(batchSize * 7);
                sb.append(deleteSql).append(" AND id IN (");
                for (int j = i; j < i + batchSize && j < idArray.length; j++) {
                    sb.append(idArray[j]).append(",");
                }
                sb.setCharAt(sb.length() - 1, ')');
                String batchSql = sb.toString();
                logger.debug("logic-delete-sql: {}", batchSql);
                results.addAndGet(sqlRunner.execute(batchSql));
            }
            metaObject.setValue("result", results.get());
        } else {
            // 执行SQL
            int result = deleteByIdsWithFill(tableInfo, idList);
            metaObject.setValue("result", result);
        }
    }

    /**
     * 获取ID列表
     * @param metaObject 元对象,可以获取到Mybatis-plus的参数对象
     * @param tableInfo 表元信息
     * @return 返回所有ID
     */
    protected List<Serializable> getIdList(MetaObject metaObject, TableInfo tableInfo) {
        String idPropertyName = tableInfo.getKeyProperty();
        Object idPropertyValue = metaObject.getValue(idPropertyName);
        if (idPropertyValue == null) {
            return Collections.emptyList();
        } else if (idPropertyValue instanceof Collection) {
            return (List<Serializable>) ((Collection) idPropertyValue).stream().map((id) -> (Serializable) id).collect(Collectors.toList());
        }
        return Collections.singletonList((Serializable) idPropertyValue);
    }

}

public class LogicDeleteByIdsWithFill extends AbstractLogicDeleteByIdsWithFill<User> {

    /**
     * 通过ID批量逻辑删除
     * @param tableMeta 逻辑删除表的表元信息
     * @param idList ID列表
     * @return 返回更新记录数
     */
    @Override
    protected Integer deleteByIdsWithFill(TableInfo tableMeta, Collection<? extends Serializable> idList) {
        // 自定义业务逻辑
        return null;
    }

    /**
     * 获取删除标记字段
     * @param tableMeta 表元信息
     * @return 返回逻辑删除字段名称
     */
    @Override
    protected String getLogicDeleteFieldName(TableInfo tableMeta) {
        return "deleteFlag";
    }

    /**
     * 是否开启了多标签
     * @param globalConfig 全局配置
     * @param idSql 待执行的SQL
     * @return 返回是否开启了多标签
     */
    @Override
    protected boolean openMultiDelete(GlobalConfig globalConfig, String idSql) {
        return false;
    }

    /**
     * 获取被逻辑删除的记录数
     * @param metaObject 元对象,可以获取到Mybatis-plus的参数对象
     * @return 返回记录数
     */
    @Override
    protected String getDeleteCount(MetaObject metaObject) {
        User user = (User) metaObject.getValue("et");
        return "SELECT COUNT(*) FROM user WHERE deleteFlag=1 AND name='" + user.getName() + "'";
    }
}

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:mybatis-plus拦截器、字段填充器、类型处理器、表名替换、SqlInjector(联合主键处理) - Python技术站

(0)
上一篇 2023年5月22日
下一篇 2023年5月22日

相关文章

  • spring boot项目application.properties文件存放及使用介绍

    介绍 application.properties是SpringBoot项目中常用的一种配置文件,可以用来定义项目的各种属性值,其中包括:数据库链接信息、各种组件的属性以及其他一些自定义属性值等等。本文将对application.properties的存放位置、使用方法以及示例进行详细的介绍。 存放位置 在一个SpringBoot项目中,applicatio…

    database 2023年5月18日
    00
  • 一文带你吃透Redis

    目录 1. 基本数据结构 2. 数据持久化 3. 高可用 4. 缓存 文章字数大约1.9万字,阅读大概需要66分钟,建议收藏后慢慢阅读!!! 1. 基本数据结构 什么是Redis Redis是一个数据库,不过与传统数据库不同的是Redis的数据库是存在内存中,所以读写速度非常快,因此 Redis被广泛应用于缓存方向。 除此之外,Redis也经常用来做分布式锁…

    Redis 2023年4月10日
    00
  • Oracle在Mybatis中SQL语句的配置方法

    下面是Oracle在Mybatis中SQL语句的配置方法的完整攻略。 1. 创建数据库连接 在Mybatis中,需要先创建一个数据库连接才能进行后续操作。可以在mybatis-config.xml文件中配置数据库连接信息,例如: <configuration> <environments default="development&…

    database 2023年5月21日
    00
  • Django中get()和filter()返回值区别详解

    Django中get()和filter()返回值区别详解 在Django的ORM中,经常会用到get()和filter()方法来获取数据库中的数据。这两个方法都可以根据指定的查询条件来获取满足条件的数据。但是它们返回的结果是有所差别的,下面我们来详细看一下它们的区别。 get()方法 get()方法用于获取满足条件的单个对象,如果查询条件返回多个对象或者没有…

    database 2023年5月18日
    00
  • Linux系统彻底卸载MySQL数据库详解

    Linux系统彻底卸载MySQL数据库详解 如果你曾经在Linux系统上面安装过MySQL数据库,那么在彻底卸载MySQL之前,你需要执行以下步骤: 步骤一:卸载MySQL服务 在Linux系统上,我们可以使用以下命令来卸载MySQL服务: sudo apt-get remove mysql-server 该命令会将MySQL数据库从系统中卸载,并且会删除M…

    database 2023年5月22日
    00
  • MySQL最佳实践之分区表基本类型

    MySQL最佳实践之分区表基本类型 分区表是MySQL5.1之后提供的表类型,它将一张大表分割成多个小表,可以大大提高查询效率。下面是分区表的几种基本类型: RANGE分区 根据指定的列值区域进行分区,语法如下: CREATE TABLE 表名( 列名 数据类型, … ) PARTITION BY RANGE(列名)( PARTITION 子表1 VAL…

    database 2023年5月21日
    00
  • redis分布式锁解决超卖问题

    1.1 redis事物   1、redis事物介绍       1. redis事物是可以一次执行多个命令,本质是一组命令的集合。       2. 一个事务中的所有命令都会序列化,按顺序串行化的执行而不会被其他命令插入       作用:一个队列中,一次性、顺序性、排他性的执行一系列命令    2、multi 指令基本使用       1. 下面指令演示了…

    Redis 2023年4月13日
    00
  • 利用rpm安装mysql 5.6版本详解

    下面为您详细讲解”利用rpm安装mysql 5.6版本详解”的完整攻略。 准备工作 在安装MySQL 5.6之前,需要先安装必要的依赖包,例如gcc、gcc-c++、cmake、ncurses-devel等。可以使用yum命令进行安装,命令如下: sudo yum install gcc gcc-c++ cmake ncurses-devel 下载MySQL…

    database 2023年5月22日
    00
合作推广
合作推广
分享本页
返回顶部