MyBatis 中的插件可以实现哪些功能

简介: MyBatis 中的插件可以实现哪些功能

MyBatis 中的插件可以实现哪些功能


概述


MyBatis 是一个流行的 Java 持久层框架,它提供了一种简单而强大的方式来访问关系型数据库。MyBatis 的核心在于 SQL 映射,它将数据库表和 Java 对象之间的映射关系定义在 XML 或注解中。MyBatis 还提供了插件机制,允许开发者在 SQL 执行过程中对其进行拦截和修改。本文将介绍 MyBatis 插件的基本原理和常见用法。


image.png


插件机制的基本原理


MyBatis 插件机制是基于 Java 动态代理机制实现的。它允许开发者在 SQL 执行过程中对其进行拦截和修改,从而实现一些自定义功能。插件机制的核心在于 Interceptor 接口和 Plugin 类,其中 Interceptor 接口定义了插件的具体实现,而 Plugin 类则用于生成代理对象。


Interceptor 接口


Interceptor 接口定义了 MyBatis 插件的具体实现。它有三个方法:


  1. intercept(Invocation invocation):该方法用于拦截 SQL 执行过程。Invocation 对象包含了执行 SQL 所需的信息,开发者可以在该方法中对 SQL 进行修改或增强。
  2. plugin(Object target):该方法用于生成代理对象。开发者需要返回一个代理对象,该对象会自动拦截 SQL 执行过程。
  3. setProperties(Properties properties):该方法用于设置插件的属性。开发者可以在该方法中读取和设置插件的配置信息。


Plugin 类


Plugin 类用于生成代理对象。它有两个静态方法:


  1. wrap(Object target, Interceptor interceptor):该方法用于生成代理对象。target 参数表示被代理的对象,interceptor 参数表示插件的具体实现。
  2. wrap(Object target, Interceptor interceptor, String[] interceptorNames):该方法用于生成代理对象。target 参数表示被代理的对象,interceptor 参数表示插件的具体实现,interceptorNames 参数表示其他插件的名称,用于确定插件的执行顺序。


常见插件的用法


分页插件


分页是 Web 应用程序中常用的功能之一,它可以帮助用户浏览大量数据。MyBatis 提供了分页支持,但是需要在 SQL 中手动编写分页逻辑。为了简化分页操作,可以使用 MyBatis 分页插件。该插件会自动拦截 SQL 执行过程,并在 SQL 中添加分页逻辑。


插件实现


下面是一个简单的分页插件实现:


@Intercepts({
    @Signature(type = StatementHandler.class, method = "prepare", args = {Connection.class, Integer.class})
})
public class PaginationInterceptor implements Interceptor {
    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        StatementHandler statementHandler = (StatementHandler) invocation.getTarget();
        BoundSql boundSql = statementHandler.getBoundSql();
        Object parameterObject = boundSql.getParameterObject();
        if (parameterObject instanceof PageRequest) {
            PageRequest pageRequest = (PageRequest) parameterObject;
            String sql = boundSql.getSql();
            int count = getCount(statementHandler, boundSql);
            pageRequest.setTotal(count);
            String pageSql = getPageSql(sql, pageRequest);
            ReflectUtil.setFieldValue(boundSql, "sql", pageSql);
        }
        return invocation.proceed();
    }
    private int getCount(StatementHandler statementHandler, BoundSql boundSql) throws SQLException {
        Connection connection = statementHandler.getConnection();
        String countSql = "SELECT COUNT(*) FROM (" + boundSql.getSql() + ") tmp";
        PreparedStatement countStatement = connection.prepareStatement(countSql);
        BoundSql countBoundSql = new BoundSql(statementHandler.getConfiguration(), countSql, boundSql.getParameterMappings(), boundSql.getParameterObject());
        setParameters(count### 日志插件
MyBatis 内置了日志功能,可以输出 SQL 执行过程中的日志信息。但是,如果需要自定义日志输出格式或将日志输出到不同的目标,可以使用 MyBatis 日志插件。
#### 插件实现
下面是一个简单的日志插件实现:
```java
@Intercepts({
    @Signature(type = Executor.class, method = "update", args = {MappedStatement.class, Object.class}),
    @Signature(type = Executor.class, method = "query", args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class})
})
public class LoggingInterceptor implements Interceptor {
    private static final Logger logger = LoggerFactory.getLogger(LoggingInterceptor.class);
    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        MappedStatement mappedStatement = (MappedStatement) invocation.getArgs()[0];
        String statementId = mappedStatement.getId();
        Object parameterObject = invocation.getArgs()[1];
        BoundSql boundSql = mappedStatement.getBoundSql(parameterObject);
        String sql = boundSql.getSql().replaceAll("[\\s]+", " ");
        long start = System.currentTimeMillis();
        Object result = invocation.proceed();
        long end = System.currentTimeMillis();
        long time = end - start;
        if (time > 1) {
            String message = String.format("[MyBatis] %s: %s (%dms)", statementId, sql, time);
            logger.info(message);
        }
        return result;
    }
    @Override
    public Object plugin(Object target) {
        return Plugin.wrap(target, this);
    }
    @Override
    public void setProperties(Properties properties) {
    }
}

该插件会拦截所有的 SQL 执行操作,并输出执行日志。在 SQL 执行时间超过 1 毫秒时,会将执行时间记录在日志中。


签名插件


MyBatis 中的 SQL 语句可以使用动态 SQL 和参数映射等功能,使得 SQL 语句更加灵活。但是,这也带来了一些安全风险,因为恶意用户可能会通过参数注入攻击来执行非法 SQL 语句。为了解决这个问题,可以使用 MyBatis 签名插件。该插件会对 SQL 语句进行签名,防止参数注入攻击。


插件实现


下面是一个简单的签名插件实现:


@Intercepts({
    @Signature(type = ParameterHandler.class, method = "setParameters", args = {PreparedStatement.class})
})
public class SignatureInterceptor implements Interceptor {
    private static final String SIGNATURE = "MyBatis";
    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        ParameterHandler parameterHandler = (ParameterHandler) invocation.getTarget();
        PreparedStatement preparedStatement = (PreparedStatement) invocation.getArgs()[0];
        Object parameterObject = parameterHandler.getParameterObject();
        if (parameterObject != null) {
            Class<?> parameterClass = parameterObject.getClass();
            Field[] fields = parameterClass.getDeclaredFields();
            for (Field field : fields) {
                if (field.isAnnotationPresent(SignatureField.class)) {
                    String fieldName = field.getName();
                    Object fieldValue = ReflectUtil.getFieldValue(parameterObject, fieldName);
                    if (fieldValue != null && fieldValue instanceof String) {
                        String value = (String) fieldValue;
                        if (value.indexOf(SIGNATURE) == -1) {
                            value = value + SIGNATURE;
                            ReflectUtil.setFieldValue(parameterObject, fieldName, value);
                        }
                    }
                }
            }
        }
        return invocation.proceed();
    }
    @Override
    public Object plugin(Object target) {
        return Plugin.wrap(target, this);
    }
    @Override
    public void setProperties(Properties properties) {
    }
}

该插件会对所有参数中被 @SignatureField 注解的字段进行签名。签名内容为固定值 “MyBatis”,可以根据实际情况进行修改。在 SQL 执行过程中,如果参数中的字段值不包含该签名,插件会自动添加签名。这样可以防止参数注入攻击。


插件的配置


在使用 MyBatis 插件时,需要对其进行配置。可以使用 XML 或注解进行配置。


XML 配置


在 MyBatis 的 XML 配置文件中,可以使用 <plugins> 元素来配置插件。例如


相关实践学习
【涂鸦即艺术】基于云应用开发平台CAP部署AI实时生图绘板
【涂鸦即艺术】基于云应用开发平台CAP部署AI实时生图绘板
相关文章
|
Java 数据库连接 数据库
Spring boot 使用mybatis generator 自动生成代码插件
本文介绍了在Spring Boot项目中使用MyBatis Generator插件自动生成代码的详细步骤。首先创建一个新的Spring Boot项目,接着引入MyBatis Generator插件并配置`pom.xml`文件。然后删除默认的`application.properties`文件,创建`application.yml`进行相关配置,如设置Mapper路径和实体类包名。重点在于配置`generatorConfig.xml`文件,包括数据库驱动、连接信息、生成模型、映射文件及DAO的包名和位置。最后通过IDE配置运行插件生成代码,并在主类添加`@MapperScan`注解完成整合
1785 1
Spring boot 使用mybatis generator 自动生成代码插件
|
SQL Java 数据安全/隐私保护
发现问题:Mybatis-plus的分页总数为0,分页功能失效,以及多租户插件的使用。
总的来说,使用 Mybatis-plus 确实可以极大地方便我们的开发,但也需要我们理解其工作原理,掌握如何合适地使用各种插件。分页插件和多租户插件是其中典型,它们的运用可以让我们的代码更为简洁、高效,理解和掌握好它们的用法对我们的开发过程有着极其重要的意义。
1166 15
|
Java 数据库连接 Spring
MyBatis-Plus关键功能使用
通过本文的详细介绍,您可以系统地了解并掌握MyBatis-Plus的关键功能,进一步提高开发效率和代码质量。
645 23
|
SQL Java 数据库连接
深入 MyBatis-Plus 插件:解锁高级数据库功能
Mybatis-Plus 提供了丰富的插件机制,这些插件可以帮助开发者更方便地扩展 Mybatis 的功能,提升开发效率、优化性能和实现一些常用的功能。
2179 26
深入 MyBatis-Plus 插件:解锁高级数据库功能
|
XML SQL Java
十二、MyBatis分页插件
十二、MyBatis分页插件
546 17
|
SQL Java 数据库连接
【MyBatisPlus·最新教程】包含多个改造案例,常用注解、条件构造器、代码生成、静态工具、类型处理器、分页插件、自动填充字段
MyBatis-Plus是一个MyBatis的增强工具,在 MyBatis 的基础上只做增强不做改变,为简化开发、提高效率而生。本文讲解了最新版MP的使用教程,包含多个改造案例,常用注解、条件构造器、代码生成、静态工具、类型处理器、分页插件、自动填充字段等核心功能。
2838 6
【MyBatisPlus·最新教程】包含多个改造案例,常用注解、条件构造器、代码生成、静态工具、类型处理器、分页插件、自动填充字段
|
SQL 缓存 Java
【详细实用のMyBatis教程】获取参数值和结果的各种情况、自定义映射、动态SQL、多级缓存、逆向工程、分页插件
本文详细介绍了MyBatis的各种常见用法MyBatis多级缓存、逆向工程、分页插件 包括获取参数值和结果的各种情况、自定义映射resultMap、动态SQL
【详细实用のMyBatis教程】获取参数值和结果的各种情况、自定义映射、动态SQL、多级缓存、逆向工程、分页插件
|
SQL Java 数据库连接
解决mybatis-plus 拦截器不生效--分页插件不生效
本文介绍了在使用 Mybatis-Plus 进行分页查询时遇到的问题及解决方法。依赖包包括 `mybatis-plus-boot-starter`、`mybatis-plus-extension` 等,并给出了正确的分页配置和代码示例。当分页功能失效时,需将 Mybatis-Plus 版本改为 3.5.5 并正确配置拦截器。
6215 6
解决mybatis-plus 拦截器不生效--分页插件不生效
|
Java 数据库连接 容器
Mybatis-Plus核心功能
Mybatis-Plus核心功能
378 4
|
SQL 存储 Java
原生JDBC简单实现Mybatis核心功能
本文介绍了在Vertx项目中使用Tdengine时,因缺乏异步JDBC驱动而采用同步驱动结合`vertx.executeBlocking`实现异步查询的方法。文中详细描述了自行开发的一个简易JDBC工具,该工具实现了SQL参数绑定与返回值映射至实体类的功能,简化了原生JDBC的繁琐操作。通过具体示例展示了其实现过程及代码细节,并与原生JDBC进行了对比,突显了其便捷性和实用性。
386 5