企业云网站建设,青海媒体网站建设公司,品牌建设网站,大良用户网站建设beforeGetBoundSql 和 setProperties 都是 InnerInterceptor 接口中定义的默认方法#xff0c;可以用于自定义拦截器实现。
beforeGetBoundSql 方法会在 MyBatis 获取 BoundSql 对象之前被调用#xff0c;可以通过该方法来修改或扩展 SQL 语句#xff0c;例如添加或删除条件…beforeGetBoundSql 和 setProperties 都是 InnerInterceptor 接口中定义的默认方法可以用于自定义拦截器实现。
beforeGetBoundSql 方法会在 MyBatis 获取 BoundSql 对象之前被调用可以通过该方法来修改或扩展 SQL 语句例如添加或删除条件、修改表名等。常见的使用场景包括
数据权限控制在查询数据时自动添加当前用户可访问的数据范围的 WHERE 条件。
多租户支持在查询数据时自动添加租户 ID 的 WHERE 条件以区分不同租户的数据。
动态表名根据不同的请求参数动态修改 SQL 语句中的表名以实现数据分片或数据隔离等功能。需要注意的是修改 BoundSql 对象时需要使用 MetaObject 对象来操作属性以保证 MyBatis 的内部状态正确。
setProperties 方法会在创建拦截器实例时被调用可以用于初始化拦截器的属性或资源例如加密算法、缓存对象等。常见的使用场景包括
加密解密对数据库中的敏感数据进行加密查询数据时进行解密。
缓存优化通过缓存某些查询结果来提高系统性能可以将缓存对象作为拦截器的属性来管理。
数据库连接池创建数据库连接池对象并缓存起来减少每次请求时创建连接池的开销。需要注意的是setProperties 方法中的参数 Properties 是一个键值对集合可以通过该对象获取配置文件中定义的属性值。在编写拦截器时需要定义对应的属性并在 setProperties 方法中将其赋值给拦截器的成员变量。
代码示例 beforeGetBoundSql 和 setProperties 两个方法都是 InnerInterceptor 接口中定义的默认方法下面分别介绍其作用和示例代码。
在 MyBatis 中BoundSql 对象表示了一个 SQL 语句的信息包括 SQL 语句本身和它所需要的参数。在执行 SQL 之前MyBatis 会通过解析 XML 配置文件和 Mapper 接口生成对应的 BoundSql 对象。
beforeGetBoundSql 方法允许开发者在获取 BoundSql 对象之前进行必要的操作例如设置参数、修改 SQL 等。下面是一个示例代码
public class MyInterceptor implements InnerInterceptor {Overridepublic void beforeQuery(Executor executor, MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException {// 获取原始的 SQL 语句String sql boundSql.getSql();// 对 SQL 语句进行修改添加 WHERE 条件if (!sql.contains(WHERE)) {sql WHERE deleted 0;}// 将修改后的 SQL 语句设置回去MetaObject metaObject SystemMetaObject.forObject(boundSql);metaObject.setValue(sql, sql);}Overridepublic void setProperties(Properties properties) {// 设置拦截器属性例如将 deleted 字段从逻辑删除修改为物理删除}
}在上面的代码中beforeQuery 方法首先获取原始的 SQL 语句然后判断是否已经包含了 WHERE 条件如果没有就添加一个 WHERE 条件来控制查询的数据范围。最后再将修改后的 SQL 语句设置回去。
需要注意的是在修改 BoundSql 对象时不能直接调用其方法而是需要通过 MetaObject 对象来操作属性这样才能保证 MyBatis 的内部状态正确。
setProperties 方法允许开发者在创建拦截器实例时对其进行配置例如设置一些参数、初始化一些资源等。下面是一个示例代码
public class MyInterceptor implements InnerInterceptor {private String algorithm; // 加密算法Overridepublic void beforeUpdate(Executor executor, MappedStatement ms, Object parameter) throws SQLException {// 在更新之前对参数进行加密if (parameter instanceof BaseEntity) {BaseEntity entity (BaseEntity) parameter;entity.encrypt(algorithm);}}Overridepublic void setProperties(Properties properties) {// 设置加密算法algorithm properties.getProperty(algorithm);}
}在上面的代码中我们定义了一个成员变量 algorithm它表示加密算法。在 beforeUpdate 方法中我们首先判断参数是否为 BaseEntity 类型如果是则调用其 encrypt 方法对数据进行加密。在 setProperties 方法中我们获取配置文件中的 algorithm 属性并将其设置到拦截器实例的成员变量中以便在 beforeUpdate 方法中使用。
使用场景一加密解密
在数据库存储敏感数据时对数据进行加密在查询数据时进行解密保护数据的安全性。
public class EncryptionInterceptor implements InnerInterceptor {private String algorithm; // 加密算法Overridepublic void beforeGetBoundSql(StatementHandler sh) {// 获取原始的 SQL 语句BoundSql boundSql sh.getBoundSql();String sql boundSql.getSql();// 解密 SQL 语句String decryptedSql decryptSql(sql);// 将解密后的 SQL 语句设置回去MetaObject metaObject SystemMetaObject.forObject(boundSql);metaObject.setValue(sql, decryptedSql);}Overridepublic void setProperties(Properties properties) {// 设置加密算法algorithm properties.getProperty(algorithm);}private String decryptSql(String encryptedSql) {// 解密 SQL 语句// ...}
}在上述代码中EncryptionInterceptor 实现了 beforeGetBoundSql 方法在获取 BoundSql 对象之前对 SQL 语句进行解密操作。通过 setProperties 方法设置加密算法的属性值。
需要注意的是这只是示例代码实际的加密解密操作需要根据具体的加密算法和业务逻辑来编写。
当需要根据条件动态修改 SQL 语句时可以使用 beforeGetBoundSql 方法。下面是一个场景示例
使用场景二 假设有一个用户表 User包含 id、name、age 等字段。现在需要实现一个分页查询功能只返回年龄大于 18 岁的用户记录并且查询结果按照姓名升序排序。但是由于数据库中存储的是加密后的数据所以需要在查询之前解密数据再进行条件过滤和排序操作。
public class DecryptInterceptor implements InnerInterceptor {Overridepublic void beforeGetBoundSql(StatementHandler sh) {BoundSql boundSql sh.getBoundSql();String sql boundSql.getSql();// 解密 SQL 语句String decryptedSql decryptSql(sql);// 将解密后的 SQL 语句设置回去MetaObject metaObject SystemMetaObject.forObject(boundSql);metaObject.setValue(sql, decryptedSql);// 设置查询条件MapString, Object parameterObject (MapString, Object) boundSql.getParameterObject();parameterObject.put(minAge, 18);// 修改排序方式String originalOrderByClause boundSql.getOrderByClause();StringBuilder newOrderByClause new StringBuilder();if (StringUtils.isNotEmpty(originalOrderByClause)) {newOrderByClause.append(originalOrderByClause).append(, );}newOrderByClause.append(name ASC);metaObject.setValue(orderByClause, newOrderByClause.toString());}private String decryptSql(String sql) {// 解密 SQL 语句// ...}
}在上述代码中DecryptInterceptor 实现了 beforeGetBoundSql 方法在获取 BoundSql 对象之前解密 SQL 语句并设置查询条件和排序方式。使用 MetaObject 对象操作 BoundSql 对象的属性来实现修改。
需要注意的是这只是示例代码实际的加密解密操作需要根据具体的加密算法和业务逻辑来编写。
使用场景三
当需要在拦截器中使用一些配置信息时可以使用 setProperties 方法。下面是一个场景示例
假设有一个需求需要记录 SQL 执行时间并根据执行时间判断 SQL 是否过慢。如果 SQL 过慢需要记录日志并发出告警。为了方便配置告警阈值可以将告警阈值作为拦截器的属性在创建拦截器实例时通过配置文件进行配置。
public class SqlExecutionTimeInterceptor implements InnerInterceptor {private long threshold; // 告警阈值单位毫秒Overridepublic Object intercept(Invocation invocation) throws Throwable {long startTime System.currentTimeMillis();Object result invocation.proceed();long endTime System.currentTimeMillis();long executionTime endTime - startTime;if (executionTime threshold) {log.warn(SQL 执行时间过长耗时{}ms, executionTime);sendAlarm(executionTime);}return result;}Overridepublic void setProperties(Properties properties) {String thresholdStr properties.getProperty(threshold);threshold Long.parseLong(thresholdStr);}private void sendAlarm(long executionTime) {// 发送告警// ...}
}在上述代码中SqlExecutionTimeInterceptor 实现了 setProperties 方法在创建拦截器实例时从配置文件中读取告警阈值并保存到拦截器的属性中。在拦截器的 intercept 方法中计算 SQL 执行时间并判断是否超过告警阈值如果超过则发送告警。
需要注意的是这只是示例代码实际的告警操作需要根据具体的业务逻辑来编写。