Article
第一章:Druid 概述与核心特性
1.1 什么是 Druid?
| 概念名称 | 说明 | 注意事项 |
|---|---|---|
| Druid 定义 | Alibaba 开源的高性能数据库连接池组件,全称为 Alibaba Druid,专为监控、安全与扩展性设计。 | 注意与 Apache Druid(实时 OLAP 分析引擎)区分,二者无任何关联。 |
| 项目定位 | 不仅是连接池,还集成了 ProxyDriver、SQL Parser、Filter 扩展机制和 Web 监控台。 | 主要面向 Java 应用,尤其在 Spring Boot 生态中广泛使用。 |
| 开源地址 | GitHub 仓库:https://github.com/alibaba/druid。 | 建议通过 Maven Central 引入依赖,避免手动下载 JAR 包。 |
1.2 Druid 的核心功能与优势
| 功能类别 | 功能名称 | 说明 | 注意事项 |
|---|---|---|---|
| 连接池基础 | 连接复用与生命周期管理 | 预创建连接、自动回收空闲/失效连接、控制最大/最小连接数,避免频繁创建销毁开销。 | 需合理配置 maxActive 和 minIdle,防止资源浪费或连接耗尽。 |
| 性能优化 | PreparedStatement 缓存(PSCache) | 缓存预编译 SQL 语句,减少重复解析开销。 | 需显式开启 poolPreparedStatements=true 并设置 maxOpenPreparedStatements。 |
| 监控能力 | StatFilter 统计 | 记录 SQL 执行时间、返回行数、错误次数、ResultSet 持有时间等。 | 启用后会有约 5–15% 性能损耗。 |
| 监控能力 | Web 监控页面 | 通过 StatViewServlet 提供 HTML 和 JSON API 查看连接池与 SQL 执行详情。 | 生产环境务必配置登录认证(loginUsername/loginPassword)防止信息泄露。 |
| 安全防护 | WallFilter(SQL 防火墙) | 基于规则过滤危险 SQL(如 DROP TABLE),防御 SQL 注入。 | 默认规则较宽松,建议根据业务自定义白名单或黑名单。 |
| 安全防护 | 密码加密 | 支持通过 ConfigTools.encrypt() 对数据库密码加密存储。 | 解密需在运行时由 Druid 自动处理,配置文件中使用 password=xxx 即可。 |
| 扩展机制 | Filter-Chain 模式 | 允许开发者通过 SPI 或编程方式插入自定义 Filter,拦截 JDBC 方法调用。 | Filter 执行顺序影响行为,需注意链式调用逻辑。 |
| 诊断能力 | 连接泄漏检测 | 自动记录未关闭连接的调用栈,辅助定位资源泄漏问题。 | 需开启 removeAbandoned=true 并设置 removeAbandonedTimeout。 |
1.3 与其他连接池(HikariCP、DBCP、C3P0)对比
| 对比维度 | HikariCP | Druid | DBCP / C3P0 |
|---|---|---|---|
| 性能 | ⭐⭐⭐⭐⭐ 极致性能,纳秒级连接获取,无锁设计。 | ⭐⭐⭐ 中高性能,因监控功能存在 5–15% 开销。 | ⭐ 性能较差,已基本被社区淘汰。 |
| 内存占用 | ~130KB,极简设计。 | ~2MB,功能模块多。 | 较高,且无有效优化。 |
| 监控能力 | 无内置监控,需依赖 Spring Boot Actuator 或 AOP。 | ✅ 内置完整监控体系(SQL、连接、慢查询、Web UI)。 | 无或极其有限。 |
| 安全功能 | 无 SQL 防火墙或审计能力。 | ✅ 支持 WallFilter 防注入、操作审计、密码加密。 | 无。 |
| 扩展性 | 不支持 Filter 扩展,专注核心连接池。 | ✅ 支持 Filter-Chain 自定义扩展。 | 扩展机制弱或复杂。 |
| 适用场景 | 微服务、云原生、高并发低延迟系统(如交易系统)。 | 企业后台、金融/医疗合规系统、需深度监控与安全审计场景。 | 已不推荐用于新项目。 |
| Spring Boot 默认 | ✅ 是(2.x+ 版本默认集成)。 | ❌ 需手动引入 druid-spring-boot-starter。 | ❌ |
选型建议:
- 若追求极致性能与轻量化 → 选择 HikariCP。
- 若需要生产级监控、安全审计、故障诊断 → 选择 Druid。
第二章:快速入门与基础配置
2.1 Maven / Gradle 依赖引入
| 构建工具 | 依赖名称 | 语法 | 用途 | 注意事项 |
|---|---|---|---|---|
| Maven | Druid 核心库 | <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.2.23</version></dependency> | 引入 Druid 连接池核心功能(含 StatFilter、WallFilter 等) | 推荐使用最新稳定版(截至 2026 年为 1.2.23),避免安全漏洞。 |
| Maven | Spring Boot Starter(可选) | <dependency> <groupId>com.alibaba</groupId> <artifactId>druid-spring-boot-starter</artifactId> <version>1.2.23</version></dependency> | 自动配置 DataSource Bean,简化 Spring Boot 集成 | 若使用此 starter,无需手动定义 DruidDataSource Bean。 |
| Gradle | Druid 核心库 | implementation 'com.alibaba:druid:1.2.23' | 同 Maven 核心库功能 | 需确保项目已配置 mavenCentral() 仓库。 |
| Gradle | Spring Boot Starter(可选) | implementation 'com.alibaba:druid-spring-boot-starter:1.2.23' | 同 Maven Starter 功能 | 适用于基于 Spring Boot 的 Gradle 项目。 |
提示:可通过 Maven Repository 查询最新版本。
2.2 基础数据源配置(Java / XML / YAML)
Java 配置方式
| 配置项 | 代码示例 | 说明 | 注意事项 |
|---|---|---|---|
| 创建 DataSource | DruidDataSource dataSource = new DruidDataSource();dataSource.setUrl("jdbc:mysql://localhost:3306/test");dataSource.setUsername("root");dataSource.setPassword("123456");dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver"); | 通过编程方式设置连接参数 | 必须调用 init() 初始化连接池(或交由 Spring 管理)。 |
| 设置连接池参数 | dataSource.setInitialSize(5);dataSource.setMinIdle(5);dataSource.setMaxActive(20); | 控制连接池容量 | maxActive 在新版本中建议使用 maxTotal(兼容旧 API)。 |
XML 配置(Spring 传统配置)
| 配置项 | 代码示例 | 说明 | 注意事项 |
|---|---|---|---|
| 定义 Bean | <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"> <property name="url" value="jdbc:mysql://localhost:3306/test"/> <property name="username" value="root"/> <property name="password" value="123456"/> <property name="initialSize" value="5"/> <property name="maxActive" value="20"/></bean> | 在 applicationContext.xml 中声明 | 需确保类路径包含 MySQL 驱动。 |
YAML 配置(Spring Boot)
| 配置项 | 代码示例 | 说明 | 注意事项 |
|---|---|---|---|
| 基础连接 | spring: datasource: url: jdbc:mysql://localhost:3306/test username: root password: 123456 driver-class-name: com.mysql.cj.jdbc.Driver | 使用 Spring Boot 默认数据源配置前缀 | 若使用 druid-spring-boot-starter,Druid 会自动接管。 |
| Druid 特有参数 | spring: datasource: druid: initial-size: 5 min-idle: 5 max-active: 20 validation-query: SELECT 1 test-while-idle: true | 通过 spring.datasource.druid.* 配置 Druid 参数 | 参数名使用 kebab-case(如 max-active 对应 setMaxActive)。 |
2.3 最小可运行示例(Spring Boot / 原生 Java)
Spring Boot 示例
| 文件类型 | 内容 | 说明 | 注意事项 |
|---|---|---|---|
pom.xml | <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid-spring-boot-starter</artifactId> <version>1.2.23</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <scope>runtime</scope> </dependency></dependencies> | 引入 Web、Druid Starter、MySQL 驱动 | runtime 表示驱动仅在运行时需要。 |
application.yml | spring: datasource: url: jdbc:mysql://localhost:3306/test?useSSL=false&serverTimezone=UTC username: root password: 123456 driver-class-name: com.mysql.cj.jdbc.Driver druid: initial-size: 5 | 配置数据库连接 | 确保数据库 test 已存在且可访问。 |
| 主启动类 | @SpringBootApplicationpublic class DemoApplication { public static void main(String[] args) { SpringApplication.run(DemoApplication.class, args); }} | 启动应用 | 启动后可访问 /actuator/health 验证数据源状态。 |
原生 Java 示例(无框架)
| 文件类型 | 内容 | 说明 | 注意事项 |
|---|---|---|---|
Main.java | import com.alibaba.druid.pool.DruidDataSource;import java.sql.Connection;public class Main { public static void main(String[] args) throws Exception { DruidDataSource ds = new DruidDataSource(); ds.setUrl("jdbc:mysql://localhost:3306/test"); ds.setUsername("root"); ds.setPassword("123456"); ds.setInitialSize(1); ds.init(); Connection conn = ds.getConnection(); System.out.println("Connection OK: " + !conn.isClosed()); conn.close(); ds.close(); }} | 手动创建、使用并关闭连接池 | 必须显式调用 ds.init() 和 ds.close(),否则资源泄漏。 |
| 编译运行命令 | javac -cp ".:druid-1.2.23.jar:mysql-connector-java-8.0.33.jar" Main.javajava -cp ".:druid-1.2.23.jar:mysql-connector-java-8.0.33.jar" Main | 编译并运行(Linux/macOS) | Windows 路径分隔符为 ;,需调整 classpath。 |
验证成功标志:控制台输出 Connection OK: true。
第三章:连接池核心参数详解
3.1 基本连接参数(url、username、password、driverClassName)
| 参数名称 | 语法(Java) | 用途 | 代码示例 | 注意事项 |
|---|---|---|---|---|
url | setUrl(String url) | 指定数据库连接地址 | ds.setUrl("jdbc:mysql://localhost:3306/test?useSSL=false&serverTimezone=UTC"); | 必须符合 JDBC 规范;建议显式设置时区和字符编码(如 characterEncoding=UTF-8)。 |
username | setUsername(String username) | 数据库登录用户名 | ds.setUsername("admin"); | 生产环境建议通过配置中心或加密方式管理。 |
password | setPassword(String password) | 数据库登录密码 | ds.setPassword("secret123"); | 强烈建议使用 ConfigFilter 加密存储,避免明文泄露。 |
driverClassName | setDriverClassName(String className) | 指定 JDBC 驱动类 | ds.setDriverClassName("com.mysql.cj.jdbc.Driver"); | MySQL 8+ 必须使用 com.mysql.cj.jdbc.Driver,旧版为 com.mysql.jdbc.Driver。 |
提示:在 Spring Boot YAML 中,这些参数位于
spring.datasource.*下,而非druid子节点。
3.2 池容量控制(initialSize、minIdle、maxActive)
| 参数名称 | 语法(Java) | 用途 | 代码示例 | 注意事项 |
|---|---|---|---|---|
initialSize | setInitialSize(int size) | 连接池初始化时创建的物理连接数 | ds.setInitialSize(5); | 启动即建立连接,避免首次请求延迟;建议等于 minIdle。 |
minIdle | setMinIdle(int minIdle) | 池中保持的最小空闲连接数 | ds.setMinIdle(5); | Druid 实际以 maxActive 为准,部分版本中 minIdle 被忽略;建议设为与 initialSize 相同。 |
maxActive | setMaxActive(int maxActive) | 最大活跃连接数(含正在使用的) | ds.setMaxActive(20); | 曾用名 maxTotal,新版本兼容两者;必须 ≤ 数据库 max_connections(如 MySQL 默认 151)。 |
调优建议:
- 小型应用:
maxActive = 10~20 - 中大型应用:
maxActive = 20~50,结合压测调整 - 避免盲目设高(如 100+),会导致数据库上下文切换开销剧增
3.3 超时与空闲连接管理(maxWait、timeBetweenEvictionRunsMillis、minEvictableIdleTimeMillis)
| 参数名称 | 语法(Java) | 用途 | 代码示例 | 注意事项 |
|---|---|---|---|---|
maxWait | setMaxWait(long millis) | 获取连接的最大等待时间(毫秒) | ds.setMaxWait(3000); // 3秒 | 超时抛出 SQLException;建议设为 1000~5000ms,实现”快速失败”。 |
timeBetweenEvictionRunsMillis | setTimeBetweenEvictionRunsMillis(long millis) | 空闲连接检测线程运行间隔 | ds.setTimeBetweenEvictionRunsMillis(60000); // 60秒 | 设为 ≤0 则禁用后台清理;建议 30~60 秒。 |
minEvictableIdleTimeMillis | setMinEvictableIdleTimeMillis(long millis) | 连接空闲多久后可被回收 | ds.setMinEvictableIdleTimeMillis(300000); // 5分钟 | 仅对超过 minIdle 的连接生效;应 < 数据库 wait_timeout。 |
注意:Druid 还支持
maxEvictableIdleTimeMillis(最大空闲时间),用于强制回收长期空闲连接。
3.4 连接有效性验证(validationQuery、testOnBorrow、testWhileIdle)
| 参数名称 | 语法(Java) | 用途 | 代码示例 | 注意事项 |
|---|---|---|---|---|
validationQuery | setValidationQuery(String sql) | 用于检测连接是否有效的 SQL 语句 | ds.setValidationQuery("SELECT 1"); | 必须是轻量级查询;MySQL 用 SELECT 1,Oracle 用 SELECT 1 FROM DUAL。 |
testOnBorrow | setTestOnBorrow(boolean test) | 借出连接时是否验证有效性 | ds.setTestOnBorrow(false); | 设为 true 会显著降低性能,生产环境不推荐开启。 |
testWhileIdle | setTestWhileIdle(boolean test) | 空闲连接在后台检测时是否验证 | ds.setTestWhileIdle(true); | 推荐开启,配合 timeBetweenEvictionRunsMillis 使用,兼顾性能与安全。 |
validationQueryTimeout | setValidationQueryTimeout(int seconds) | 验证查询的超时时间(秒) | ds.setValidationQueryTimeout(5); | 防止验证 SQL 卡住;设为 >0 才生效。 |
最佳实践:
ds.setValidationQuery("SELECT 1");
ds.setTestWhileIdle(true);
ds.setTestOnBorrow(false);
ds.setTestOnReturn(false);
3.5 PreparedStatement 缓存(poolPreparedStatements、maxOpenPreparedStatements)
| 参数名称 | 语法(Java) | 用途 | 代码示例 | 注意事项 |
|---|---|---|---|---|
poolPreparedStatements | setPoolPreparedStatements(boolean pool) | 是否启用 PreparedStatement 缓存 | ds.setPoolPreparedStatements(true); | 对 Oracle/DB2 提升显著;MySQL 建议关闭(驱动层已优化)。 |
maxOpenPreparedStatements | setMaxOpenPreparedStatements(int max) | 单个连接最多缓存的 PS 数量 | ds.setMaxOpenPreparedStatements(100); | 设为 >0 时自动启用 poolPreparedStatements;过高会增加内存占用。 |
MySQL 特别说明:
- MySQL Connector/J 8.x 已内置高效 PS 缓存
- Druid 再次缓存可能造成冗余,通常设为
false - 若业务大量使用相同参数化 SQL(如 MyBatis),可尝试开启并压测对比
第四章:监控与统计功能(StatFilter)
4.1 StatFilter 启用与配置
| 配置方式 | 语法 / 方法 | 用途 | 代码示例 | 注意事项 |
|---|---|---|---|---|
| 别名方式(推荐) | setFilters("stat") | 通过字符串别名启用 StatFilter | ds.setFilters("stat"); | 别名 stat 映射到 com.alibaba.druid.filter.stat.StatFilter;支持组合如 "stat,wall"。 |
| Bean 方式(细粒度控制) | setProxyFilters(List<Filter> filters) | 通过 Java Bean 注入 StatFilter 实例 | StatFilter statFilter = new StatFilter();statFilter.setMergeSql(true);ds.setProxyFilters(Arrays.asList(statFilter)); | filters 与 proxyFilters 是叠加关系,不是互斥。 |
| 连接属性方式 | setConnectionProperties(Properties props) | 通过连接属性开启 Stat 功能 | Properties props = new Properties();props.setProperty("druid.stat.mergeSql", "true");ds.setConnectionProperties(props); | 所有 druid.stat.* 属性均支持此方式。 |
| JVM 参数方式 | 启动参数 | 全局生效 | -Ddruid.stat.mergeSql=true -Ddruid.filters=stat | 适用于无法修改代码的场景,但优先级低于程序配置。 |
注意:仅设置
filters="stat"不会自动开启 SQL 日志输出,需额外配置日志框架(如 SLF4J)或开启statementLogEnabled。
4.2 Web 监控页面集成(StatViewServlet)
| 配置项 | 语法(Spring Boot YAML) | 用途 | 示例值 | 注意事项 |
|---|---|---|---|---|
| servlet 路径 | spring.datasource.druid.stat-view-servlet.url-pattern | 设置监控页面访问路径 | /druid/* | 默认即为此值;可自定义如 /monitor/*。 |
| 启用开关 | spring.datasource.druid.stat-view-servlet.enabled | 是否启用 Web 监控 | true | 默认为 true;生产环境建议显式控制。 |
| 访问白名单 | spring.datasource.druid.stat-view-servlet.allow | 允许访问的 IP 地址(逗号分隔) | 127.0.0.1,192.168.1.0/24 | 留空表示允许所有;生产环境必须限制。 |
| 访问黑名单 | spring.datasource.druid.stat-view-servlet.deny | 拒绝访问的 IP(优先级高于 allow) | 192.168.1.100 | 可用于封禁特定 IP。 |
| 登录用户名 | spring.datasource.druid.stat-view-servlet.login-username | 监控页面登录账号 | admin | 必须配合密码使用,否则无需认证。 |
| 登录密码 | spring.datasource.druid.stat-view-servlet.login-password | 监控页面登录密码 | druid123 | 生产环境必须设置强密码。 |
手动注册 Servlet(非 Spring Boot)
| 步骤 | 代码示例 | 说明 |
|---|---|---|
| 注册 StatViewServlet | @WebServlet(urlPatterns = "/druid/*", initParams = { @WebInitParam(name = "loginUsername", value = "admin"), @WebInitParam(name = "loginPassword", value = "druid123"), @WebInitParam(name = "allow", value = "127.0.0.1")})public class DruidStatViewServlet extends StatViewServlet {} | 需在 web.xml 或使用 @WebServlet 注解 |
⚠️ 安全警告:未设密码的 /druid 页面可能泄露数据库结构、SQL 执行详情,存在严重信息泄露风险。
4.3 SQL 执行统计、慢查询分析(slowSqlMillis、logSlowSql)
| 参数名称 | 语法(Java) | 用途 | 代码示例 | 注意事项 |
|---|---|---|---|---|
slowSqlMillis | setSlowSqlMillis(long millis) | 定义”慢 SQL”的阈值(毫秒) | statFilter.setSlowSqlMillis(1000); | 默认为 3000ms;建议根据业务响应要求调整(如 500ms)。 |
logSlowSql | setLogSlowSql(boolean log) | 是否将慢 SQL 输出到日志 | statFilter.setLogSlowSql(true); | 需确保日志框架已配置,且级别为 INFO 或 DEBUG。 |
mergeSql | setMergeSql(boolean merge) | 合并未参数化 SQL(如 id=1, id=2 → id=?) | statFilter.setMergeSql(true); | 极大提升统计准确性;可通过 filters="mergeStat" 快速启用。 |
statementLogEnabled | setStatementLogEnabled(boolean enabled) | 是否记录所有 Statement 执行日志 | ds.setStatementLogEnabled(true); | 性能影响较大,仅限开发/测试环境使用。 |
statementExecutableSqlLogEnable | setStatementExecutableSqlLogEnable(boolean enable) | 是否打印带参数的实际 SQL | ds.setStatementExecutableSqlLogEnable(true); | 需配合 statementLogEnabled=true 使用。 |
YAML 配置示例:
spring:
datasource:
druid:
filter:
stat:
enabled: true
slow-sql-millis: 1000
log-slow-sql: true
merge-sql: true
4.4 监控访问控制(allow、deny、loginUsername、loginPassword)
| 控制维度 | 配置项 | 作用机制 | 示例 | 注意事项 |
|---|---|---|---|---|
| IP 白名单 | allow | 仅允许列表中的 IP 访问监控页面 | 127.0.0.1,10.0.0.0/8 | 支持 CIDR 格式;留空 = 允许所有。 |
| IP 黑名单 | deny | 拒绝列表中的 IP(即使在 allow 中) | 192.168.1.100 | 优先级高于 allow。 |
| 基本身份认证 | loginUsername + loginPassword | HTTP Basic Auth 登录验证 | loginUsername: adminloginPassword: securePass! | 必须同时设置两者才生效;密码建议使用复杂字符。 |
| 资源排除 | exclusions(WebStatFilter) | 不统计静态资源请求 | *.js,*.css,/druid/* | 防止监控数据被无关请求污染。 |
WebStatFilter 配置(用于 URI 监控)
| 配置项 | YAML 示例 | 说明 |
|---|---|---|
exclusions | spring.datasource.druid.web-stat-filter.exclusions: "*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*" | 过滤不监控的资源路径 |
session-stat-max-count | spring.datasource.druid.web-stat-filter.session-stat-max-count: 1000 | 最大会话统计数 |
profile-enable | spring.datasource.druid.web-stat-filter.profile-enable: true | 开启请求耗时采样(可查看 SQL 执行链路) |
完整安全建议:
- 生产环境必须设置
allow和loginUsername/loginPassword - 禁止将
/druid路径暴露到公网 - 通过 Nginx 或 API 网关增加额外鉴权层
第五章:安全防护机制
5.1 SQL 防火墙(WallFilter)原理与配置
| 配置方式 | 语法 / 方法 | 用途 | 代码示例 | 注意事项 |
|---|---|---|---|---|
| 别名启用 | setFilters("wall") | 快速启用 WallFilter(默认 MySQL 规则) | ds.setFilters("wall"); | 自动根据 driverClassName 选择方言(如 Oracle、PostgreSQL)。 |
| 指定方言 | wallConfig.setDbType(String dbType) | 显式设置数据库类型 | WallConfig config = new WallConfig();config.setDbType(JdbcConstants.MYSQL);WallFilter wallFilter = new WallFilter();wallFilter.setConfig(config); | 支持常量:JdbcConstants.MYSQL、ORACLE、POSTGRESQL 等。 |
| 允许多语句 | wallConfig.setMultiStatementAllow(boolean allow) | 是否允许单次执行多条 SQL(如 ; DROP TABLE) | config.setMultiStatementAllow(false); // 默认 false | 生产环境必须设为 false,防止堆叠注入攻击。 |
| 允许删除表 | wallConfig.setDeleteAllow(boolean allow) | 是否允许 DELETE 无 WHERE 条件 | config.setDeleteAllow(false); | 默认 true,建议关闭以防止误删全表。 |
| 允许更新表 | wallConfig.setUpdateAllow(boolean allow) | 是否允许 UPDATE 无 WHERE 条件 | config.setUpdateAllow(false); | 同上,防止全表更新。 |
| 允许函数调用 | wallConfig.setSchemaCheck(boolean check) | 是否校验 schema/函数权限 | config.setSchemaCheck(true); | 可限制调用 LOAD_FILE()、SLEEP() 等危险函数。 |
YAML 配置示例(Spring Boot):
spring:
datasource:
druid:
filter:
wall:
enabled: true
db-type: mysql
config:
multi-statement-allow: false
delete-allow: false
update-allow: false
注意:WallFilter 默认策略较宽松,需根据业务需求收紧规则。
5.2 数据库密码加密(ConfigFilter 与 ConfigTools)
| 组件 | 方法 / 工具 | 用途 | 代码示例 | 注意事项 |
|---|---|---|---|---|
| ConfigTools | ConfigTools.encrypt(String password) | 生成公钥加密后的密文 | String encrypted = ConfigTools.encrypt("myPassword123"); | 输出格式如 bXlQYXNzd29yZDEyMw==(Base64 编码的 AES 密文)。 |
| ConfigFilter | setConnectionProperties("config.decrypt=true") | 告知 Druid 自动解密密码 | ds.setConnectionProperties("config.decrypt=true"); | 必须配合 password=密文 使用。 |
| 公钥指定 | config.decrypt.key(可选) | 使用自定义公钥(非默认) | props.setProperty("config.decrypt.key", "MFwwD..."); | 默认使用内置密钥;自定义需同时在加密和解密端一致。 |
| Maven 插件加密 | mvn druid:encrypt -Ddruid.password=myPass | 通过 Maven 命令行加密 | 执行后输出密文到控制台 | 需在 pom.xml 中引入 druid-maven-plugin。 |
完整 Java 配置示例
| 步骤 | 代码 |
|---|---|
| 1. 加密密码(开发阶段) | String pwd = ConfigTools.encrypt("root123"); // 得到密文 |
| 2. 配置数据源 | DruidDataSource ds = new DruidDataSource();ds.setUrl("jdbc:mysql://localhost/test");ds.setUsername("root");ds.setPassword("密文");Properties props = new Properties();props.setProperty("config.decrypt", "true");ds.setConnectionProperties(props); |
安全提示:
- 密文仍可能被反编译获取,建议结合配置中心(如 Apollo、Nacos)动态下发
- 不要将密文硬编码在 Git 仓库中
5.3 防注入规则自定义
| 自定义方式 | 方法 / 配置 | 用途 | 示例 | 注意事项 |
|---|---|---|---|---|
| 白名单 SQL | wallProvider.addWhiteSql(String sql) | 添加允许执行的 SQL 模板 | wallProvider.addWhiteSql("SELECT * FROM users WHERE id = ?"); | 需在初始化后、连接池启动前调用。 |
| 黑名单关键词 | wallConfig.setBlackList(List<String>) | 禁止包含特定关键词的 SQL | List<String> black = Arrays.asList("SLEEP", "BENCHMARK");config.setBlackList(black); | 区分大小写;支持正则(需开启 blackListRegex=true)。 |
| 自定义回调 | wallFilter.setSqlStatCallback(SqlStatCallback callback) | 拦截 SQL 并自定义处理逻辑 | wallFilter.setSqlStatCallback((sql, result) -> { if (!result.isExecute()) { log.warn("Blocked SQL: " + sql); }}); | 可用于告警、审计日志记录。 |
| 规则文件加载 | wallConfig.setRuleFile(String path) | 从外部文件加载规则 | config.setRuleFile("classpath:wall-rules.xml"); | 文件需符合 Druid Wall 规则 XML 格式。 |
自定义 WallProvider 示例(高级)
| 场景 | 代码片段 |
|---|---|
| 动态白名单 | WallProvider provider = WallProvider.create(JdbcConstants.MYSQL);provider.getConfig().setSelectAllColumnAllow(false);// 从数据库或配置中心加载白名单List<String> allowed = loadFromConfigCenter();allowed.forEach(provider::addWhiteSql);WallFilter wallFilter = new WallFilter();wallFilter.setProvider(provider); |
规则优先级:
白名单 > 黑名单 > 内置规则
即:若 SQL 在白名单中,即使含黑名单关键词也会放行。
典型禁用项建议:
SELECT *(设selectAllColumnAllow=false)- 无 WHERE 的 DELETE/UPDATE
- 多语句(
multiStatementAllow=false) - 危险函数:
LOAD_FILE、EXECUTE、xp_cmdshell(SQL Server)
第六章:扩展与高级功能
6.1 Filter 链机制与自定义 Filter 开发
| 概念 / 方法 | 语法 / 接口 | 用途 | 代码示例 | 注意事项 |
|---|---|---|---|---|
| Filter 接口 | com.alibaba.druid.filter.Filter | 所有 Druid Filter 的基接口 | public class MyCustomFilter implements Filter { ... } | 必须实现 connection_connect、statement_execute 等拦截方法。 |
| 方法拦截命名规则 | xxx_before / xxx_after | 在目标 JDBC 方法执行前后插入逻辑 | public void statement_execute_before(StatementProxy stmt, String sql) { System.out.println("Executing: " + sql);} | 方法名需严格匹配(如 connection_close_before)。 |
| 注册 Filter(Java) | ds.setProxyFilters(List<Filter>) | 将自定义 Filter 加入链 | List<Filter> filters = new ArrayList<>();filters.add(new MyCustomFilter());ds.setProxyFilters(filters); | 执行顺序 = 列表顺序;StatFilter/WallFilter 可共存。 |
| 注册 Filter(别名) | ds.setFilters("stat,myfilter") | 通过 SPI 别名注册 | 需在 META-INF/druid-filter.properties 中声明:myfilter=com.example.MyCustomFilter | 适用于模块化部署,避免硬编码依赖。 |
| 获取原始连接 | conn.getRawConnection() | 在 Filter 中访问底层 Connection | Connection raw = ((DruidPooledConnection) conn).getRawConnection(); | 谨慎使用,可能绕过连接池管理。 |
自定义 Filter 完整示例:
public class AuditLogFilter extends FilterEventAdapter {
@Override
public void statementExecuteBefore(StatementProxy statement, String sql) throws SQLException {
System.out.println("[AUDIT] SQL: " + sql);
}
}
6.2 日志集成(Log4j、SLF4J、JDK Logging)
| 日志框架 | 配置方式 | 用途 | 示例配置 | 注意事项 |
|---|---|---|---|---|
| SLF4J(推荐) | 自动适配 | Druid 默认优先使用 SLF4J 输出日志 | 无需额外配置,引入 slf4j-api + 实现(如 Logback)即可 | 若同时存在多个日志框架,需排除冲突依赖。 |
| Log4j2 | 设置系统属性 | 强制使用 Log4j2 | 启动参数:-Ddruid.logType=log4j2 | 需确保 log4j-core 在 classpath。 |
| JDK Logging | 默认回退 | 当无其他日志框架时使用 | 无需配置 | 格式简陋,不建议生产使用。 |
| 关闭日志 | -Ddruid.logType=none | 禁用所有 Druid 内部日志 | java -Ddruid.logType=none -jar app.jar | 适用于性能敏感场景。 |
| StatFilter 日志 | statFilter.setLogSlowSql(true) | 输出慢 SQL 到日志 | 见第四章 4.3 节 | 日志级别为 WARN(慢 SQL)或 INFO(普通统计)。 |
Maven 依赖示例(SLF4J + Logback):
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>2.0.12</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.4.14</version>
</dependency>
6.3 JMX 监控支持
| 功能 | 配置方式 | 用途 | 代码 / 配置示例 | 注意事项 |
|---|---|---|---|---|
| 启用 JMX | ds.setEnableJmx(true) | 将连接池指标注册为 MBean | DruidDataSource ds = new DruidDataSource();ds.setEnableJmx(true); | 默认为 false;Spring Boot 中需显式开启。 |
| JMX 对象名 | ds.setJmxObjectName(String name) | 自定义 MBean 名称 | ds.setJmxObjectName("com.example:type=MyDB"); | 避免名称冲突;格式需符合 JMX 规范。 |
| 查看指标 | 使用 jconsole 或 jvisualvm | 实时监控活跃连接、等待数等 | 启动应用后运行 jconsole → 连接进程 → MBean 标签 | 需确保应用未禁用 JMX(如 -Dcom.sun.management.jmxremote)。 |
| 关键 MBean 属性 | — | 可读取的运行时指标 | ActiveCount, PoolingCount, ConnectCount, CloseCount, WaitThreadCount | 支持通过 JMX API 编程获取。 |
| Spring Boot 集成 | management.endpoints.jmx.exposure.include=* | 通过 Actuator 暴露 JMX 端点 | 在 application.yml 中配置 | 需引入 spring-boot-starter-actuator。 |
YAML 配置(Spring Boot + JMX):
spring:
datasource:
druid:
enable-jmx: true
management:
endpoints:
jmx:
exposure:
include: "*"
6.4 多数据源配置
| 实现方式 | 配置方法 | 用途 | 示例说明 | 注意事项 |
|---|---|---|---|---|
| 手动定义多个 Bean | @Bean("db1") DruidDataSource ds1()@Bean("db2") DruidDataSource ds2() | 简单多数据源(无事务跨库) | 分别配置不同 URL/用户名 | 需手动管理 @Qualifier 注入。 |
| Dynamic DataSource(推荐) | 使用 dynamic-datasource-spring-boot-starter | 支持注解切换数据源 | @DS("slave") public List<User> list() { ... } | 与 Druid 完美兼容,自动包装为 DruidDataSource。 |
| AbstractRoutingDataSource | 继承 Spring 抽象类 | 自定义路由逻辑(如分库) | 重写 determineCurrentLookupKey() 返回数据源 key | 需自行初始化多个 DruidDataSource 实例。 |
| YAML 配置(Spring Boot) | spring.datasource.dynamic.datasource.master.url=...spring.datasource.dynamic.datasource.slave.url=... | 声明式多数据源 | 依赖 com.baomidou:dynamic-datasource-spring-boot-starter | 主从、读写分离开箱即用。 |
| 事务管理 | @Transactional + DataSourceTransactionManager | 保证单数据源事务一致性 | 每个数据源需独立配置 TransactionManager | 不支持跨数据源分布式事务(需 Seata 等)。 |
手动多数据源 Java 配置示例
| 文件 | 内容 |
|---|---|
DataSourceConfig.java | @Configurationpublic class DataSourceConfig { @Bean("master") @ConfigurationProperties("spring.datasource.druid.master") public DataSource master() { return new DruidDataSource(); } @Bean("slave") @ConfigurationProperties("spring.datasource.druid.slave") public DataSource slave() { return new DruidDataSource(); }} |
application.yml | spring: datasource: druid: master: url: jdbc:mysql://localhost/master username: root password: 123 slave: url: jdbc:mysql://localhost/slave username: root password: 123 |
最佳实践:
- 读写分离 → 使用
dynamic-datasource - 分库分表 → 结合 ShardingSphere
- 简单双库 → 手动
@Bean+@Qualifier
第七章:生产环境最佳实践
7.1 性能调优建议(连接数、超时、KeepAlive)
| 调优维度 | 参数名称 | 推荐值 | 说明 | 注意事项 |
|---|---|---|---|---|
| 连接池容量 | initialSize | = minIdle(如 5~10) | 避免启动时首次请求延迟 | 不宜过大,防止数据库连接堆积 |
minIdle | 5~10 | 保持最小空闲连接 | Druid 实际以 maxActive 为主,此值影响不大 | |
maxActive | 20~50(压测后确定) | 最大并发连接数 | 必须 ≤ 数据库 max_connections(MySQL 默认 151) | |
| 获取超时 | maxWait | 1000~3000 ms | 获取连接最大等待时间 | 超时应快速失败,避免线程阻塞雪崩 |
| 空闲检测 | timeBetweenEvictionRunsMillis | 30000~60000 ms | 后台清理线程间隔 | 设为 ≤0 则禁用清理 |
minEvictableIdleTimeMillis | 300000 ms(5分钟) | 空闲连接可回收时间 | 应 < 数据库 wait_timeout(MySQL 默认 8 小时) | |
| 连接保活 | keepAlive | true | 启用连接保活机制 | 需配合 keepAliveBetweenTimeMillis 使用 |
keepAliveBetweenTimeMillis | 1800000 ms(30分钟) | 连接空闲多久后执行保活 SQL | 仅对超过 minIdle 的连接生效 | |
validationQuery | SELECT 1(MySQL) | 保活/验证 SQL | 必须轻量、无副作用 | |
| 预编译缓存 | poolPreparedStatements | false(MySQL)true(Oracle) | 是否启用 PS 缓存 | MySQL 驱动已优化,重复缓存反增开销 |
压测建议:
- 使用 JMeter / Gatling 模拟峰值流量
- 监控数据库
Threads_connected和应用ActiveCount - 调整
maxActive直至吞吐稳定、错误率 < 0.1%
7.2 故障检测与自动恢复(removeAbandoned、breakAfterAcquireFailure)
| 参数名称 | 推荐值 | 用途 | 代码示例 | 注意事项 |
|---|---|---|---|---|
removeAbandoned | true | 自动回收疑似泄漏的连接 | ds.setRemoveAbandoned(true); | 仅用于诊断,非根治方案 |
removeAbandonedTimeout | 1800 秒(30分钟) | 连接未归还超过此时间则强制回收 | ds.setRemoveAbandonedTimeout(1800); | 应远大于业务最长事务时间 |
logAbandoned | true | 记录连接泄漏时的调用栈 | ds.setLogAbandoned(true); | 日志级别为 WARN;可用于定位代码问题 |
breakAfterAcquireFailure | true | 获取连接失败后中断后续获取 | ds.setBreakAfterAcquireFailure(true); | 防止数据库宕机时线程持续重试耗尽资源 |
failFast | true | 启动时立即测试连接有效性 | ds.setFailFast(true); | 避免应用启动成功但数据库不可用 |
asyncInit | true | 异步初始化连接池 | ds.setAsyncInit(true); | 加快 Spring Boot 启动速度 |
典型场景:
- 数据库重启 →
breakAfterAcquireFailure=true可快速失败,配合 Hystrix/Sentinel 熔断 - 连接泄漏 →
removeAbandoned=true+logAbandoned=true辅助排查
7.3 与 Spring Boot / MyBatis / JPA 集成方案
| 框架组合 | 集成方式 | 关键依赖 | 配置要点 | 注意事项 |
|---|---|---|---|---|
| Spring Boot + Druid | 使用 druid-spring-boot-starter | <dependency> <groupId>com.alibaba</groupId> <artifactId>druid-spring-boot-starter</artifactId> <version>1.2.23</version></dependency> | 配置前缀:spring.datasource.druid.* | 自动注册 DataSource、StatViewServlet、WebStatFilter |
| + MyBatis | 引入 mybatis-spring-boot-starter | <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>3.0.3</version></dependency> | Mapper 扫描:@MapperScan("com.example.mapper") | 无需额外配置,MyBatis 自动使用 Druid DataSource |
| + JPA (Hibernate) | 使用 Spring Data JPA | <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId></dependency> | Hibernate 自动适配 DataSource | 建议关闭 JPA 自建连接池:spring.jpa.database-platform=... |
| 监控集成 | 开启 StatFilter + Web UI | 已包含在 starter 中 | spring.datasource.druid.stat-view-servlet.enabled=true | 生产环境务必设密码和 IP 白名单 |
| 多数据源 | 结合 dynamic-datasource | <dependency> <groupId>com.baomidou</groupId> <artifactId>dynamic-datasource-spring-boot-starter</artifactId> <version>4.2.0</version></dependency> | 使用 @DS("slave") 注解切换 | 自动包装为 DruidDataSource,支持监控 |
YAML 完整示例(Spring Boot + MyBatis + Druid):
spring:
datasource:
url: jdbc:mysql://db:3306/app
username: user
password: ENC(xxx) # 若使用加密
driver-class-name: com.mysql.cj.jdbc.Driver
druid:
initial-size: 5
max-active: 30
max-wait: 3000
validation-query: SELECT 1
test-while-idle: true
stat-view-servlet:
enabled: true
login-username: admin
login-password: securePass!
allow: 10.0.0.0/8
mybatis:
mapper-locations: classpath:mapper/*.xml
7.4 容器化部署注意事项(Docker / Kubernetes)
| 场景 | 配置项 / 策略 | 说明 | 示例 / 建议 | 注意事项 |
|---|---|---|---|---|
| Docker 镜像 | 基础镜像选择 | 使用官方 JDK 镜像 | FROM eclipse-temurin:17-jre-alpine | 避免使用 latest 标签 |
| 配置外置 | 使用环境变量 | 替代硬编码配置 | ENV SPRING_DATASOURCE_URL=jdbc:mysql://host/db | 推荐结合 ConfigMap(K8s) |
| 健康检查 | /actuator/health 或自定义端点 | K8s Liveness/Readiness 探针 | livenessProbe: httpGet: path: /druid/health.html port: 8080 initialDelaySeconds: 60 | Druid 无内置 /health,需通过 Actuator 或自定义 Servlet |
| 资源限制 | CPU/Memory 限制 | 防止单 Pod 耗尽节点资源 | resources: limits: memory: "512Mi" cpu: "500m" | maxActive 应与内存配比(每连接约 1~2MB) |
| 网络策略 | 限制 /druid 访问 | 仅允许运维网段访问监控页 | networkPolicy: ingress: - from: - ipBlock: cidr: 10.10.0.0/16 | 避免将 stat-view-servlet 暴露到公网 |
| 日志收集 | stdout/stderr 输出 | 便于 Fluentd / Loki 采集 | 确保日志框架输出到控制台 | 避免写入容器内文件(Pod 重建丢失) |
| 连接池预热 | 启动时执行 SQL | 避免冷启动延迟 | @PostConstruct public void warmUp() { ... } | 可查询 SELECT 1 初始化连接 |
Kubernetes Deployment 片段示例:
env:
- name: SPRING_DATASOURCE_DRUID_STAT-VIEW-SERVLET_LOGIN-PASSWORD
valueFrom:
secretKeyRef:
name: druid-secret
key: password
resources:
requests:
memory: "256Mi"
cpu: "200m"
limits:
memory: "512Mi"
cpu: "500m"
livenessProbe:
httpGet:
path: /actuator/health
port: 8080
initialDelaySeconds: 60
periodSeconds: 30
安全加固:
- 禁用
filters="stat"的远程访问(或严格限 IP) - 数据库密码通过 Secret 注入,禁止明文写入 YAML
- 启用 WallFilter 防注入
第八章:底层原理与架构解析
8.1 DruidDataSource 初始化流程
| 阶段 | 方法 / 步骤 | 作用 | 关键代码逻辑 | 注意事项 |
|---|---|---|---|---|
| 双重检查锁 | init() 入口 | 确保仅初始化一次 | if (inited) return;lock.lockInterruptibly();if (inited) return; | 使用 ReentrantLock 非公平锁,避免死锁(参考 issue #2980) |
| 驱动加载 | DruidDriver.getInstance() | 注册 Druid 自身为 JDBC Driver | static { registerDriver(new DruidDriver()); } | 支持 jdbc:druid://... 协议(较少使用) |
| 配置注入 | configFromPropety(Properties) | 从 Properties 加载参数 | setUrl(props.getProperty("druid.url")); | Spring Boot 中由 DruidDataSourceAutoConfigure 完成绑定 |
| Filter 初始化 | for (Filter f : filters) f.init(this); | 初始化所有 Filter | 包括 StatFilter、WallFilter 等 | SPI 加载的 Filter 通过 initFromSPIServiceLoader() 注入 |
| 数据库类型识别 | JdbcUtils.getDbType(jdbcUrl, null) | 自动推断 DB 类型 | 返回 DbType.mysql、oracle 等 | 影响 SQL 解析器、防火墙规则选择 |
| 连接池预热 | 异步创建初始连接 | 提升首次请求性能 | if (asyncInit && createScheduler != null) { submitCreateTask(true); } | 同步初始化会阻塞 init() 直到 initialSize 连接建立完成 |
| 状态标记 | inited = true; | 标记初始化完成 | 最后一步,释放锁 | 之后 getConnection() 不再触发初始化 |
初始化顺序图(简化):
new DruidDataSource() → setXXX() → init() →
1. 加锁 + 双重检查
2. 加载驱动、解析 URL
3. 初始化 Filters
4. 校验参数(如 maxActive > 0)
5. 启动后台线程(evictor、createScheduler)
6. 标记 inited = true
8.2 连接获取与归还机制
连接获取(getConnection())
| 方法 | 作用 | 关键逻辑 | 注意事项 |
|---|---|---|---|
getConnection() | 公开入口 | 调用 getConnection(maxWait) | maxWait 默认 -1(无限等待) |
getConnection(long maxWaitMillis) | 主流程 | 1. 调用 init()(若未初始化)2. 若有 Filter,走 filterChain.dataSource_connect()3. 否则调用 getConnectionDirect() | Filter 链可拦截并修改行为 |
getConnectionDirect(long maxWaitMillis) | 直接获取 | 1. 循环尝试 getConnectionInternal()2. 若 testOnBorrow=true,验证连接有效性3. 无效则 discardConnection() 并重试 | 支持重试(notFullTimeoutRetryCount 次) |
getConnectionInternal(long maxWaitNanos) | 核心实现 | 1. 若池空且未满,直接创建物理连接 2. 否则从 connections[] 数组尾部取(takeLast()/pollLast())3. 若无可用连接,等待 notEmpty 条件 | 使用 ReentrantLock + Condition 实现生产者-消费者模型 |
连接归还(close())
| 方法 | 作用 | 关键逻辑 | 注意事项 |
|---|---|---|---|
DruidPooledConnection.close() | 代理 close | 1. CAS 设置 closing=1 防重复关闭2. 触发 ConnectionEventListener3. 调用 recycle() | 实际不关闭物理连接,而是归还池中 |
recycle() | 归还主逻辑 | 1. 若未被标记为 abandoned,调用 dataSource.recycle(this)2. 清空 holder、conn 引用 | 防止内存泄漏 |
DruidDataSource.recycle(DruidPooledConnection) | 池回收 | 1. 重置连接状态(autoCommit、catalog 等) 2. 放回 connections[] 数组头部3. 唤醒等待线程( notEmpty.signal()) | 重置操作确保下次获取时状态干净 |
关键数据结构:
DruidConnectionHolder[] connections:连接池底层数组ReentrantLock lock+Condition notEmpty,empty:并发控制AtomicInteger activeCount:活跃连接计数
8.3 Filter-Chain 执行模型
| 组件 | 作用 | 执行流程 | 示例方法 |
|---|---|---|---|
| Filter 接口 | 定义拦截点 | 所有扩展 Filter 必须实现此接口 | connection_connect, statement_execute |
| FilterChainImpl | 责任链实现 | 1. 构造时传入 Filter 列表 2. 调用 xxx() 时依次执行 filter.xxx_before() → 下一 filter → filter.xxx_after() | dataSource_connect(DataSourceProxy, long) |
| 方法命名映射 | 自动匹配 | statement.execute(sql) → statementExecuteBefore(stmt, sql) → executeQuery() → statementExecuteAfter(...) | 方法名需严格遵循驼峰转下划线规则 |
| 执行顺序 | 用户定义 | filters 列表顺序即执行顺序 | StatFilter → WallFilter → 自定义 Filter |
| 短路机制 | 支持中断 | 某 Filter 可抛出异常或返回 false 中断链 | WallFilter 拦截 SQL 时直接抛 SQLException |
Filter 方法签名示例
| JDBC 操作 | 对应 Filter 方法 | 参数说明 |
|---|---|---|
Connection conn = ds.getConnection() | connection_connect(DataSourceProxy, long maxWait) | 可修改 maxWait 或抛异常拒绝连接 |
stmt.executeQuery(sql) | statement_executeQuery(StatementProxy, String sql) | 可记录日志、修改 SQL、校验权限 |
rs.next() | resultSet_next(ResultSetProxy) | 可统计行数、脱敏数据 |
设计优势:
- 无侵入式扩展
- 可组合多个功能(监控 + 防火墙 + 审计)
- 性能损耗可控(仅在启用时生效)
8.4 SQL 解析器(SQLParser)工作原理
| 组件 | 作用 | 技术细节 | 应用场景 |
|---|---|---|---|
| SQLParser 接口 | SQL 语法解析入口 | 基于手写递归下降解析器(非 ANTLR) | 支持 MySQL、Oracle、PostgreSQL 等方言 |
| SQLStatementParser | 语句级解析 | 将 SQL 字符串转为 AST(抽象语法树) | 如 SELECT * FROM t → SQLSelectStatement 对象 |
| SchemaStatVisitor | 语义分析 | 遍历 AST 提取表名、列名、条件等 | 用于 WallFilter 的权限校验、SQL 统计 |
| 词法分析 | Tokenization | 识别关键字、标识符、常量等 | 如 SELECT → Token.SELECT |
| 语法分析 | Parsing | 构建语法树,校验合法性 | 非法 SQL(如 SELECT FROM)抛 ParserException |
| 方言适配 | DbType 驱动 | 不同数据库使用不同 Parser 实现 | MySqlStatementParser, OracleStatementParser |
解析流程示例(SELECT id, name FROM users WHERE age > 18)
| 步骤 | 输出 |
|---|---|
| 1. 词法分析 | [SELECT, id, ,, name, FROM, users, WHERE, age, >, 18] |
| 2. 语法分析 | 构建 SQLSelectStatement 对象 |
| 3. 语义分析(Visitor) | 提取:表 users;列 id, name, age;条件 age > 18 |
性能优化:
- 缓存解析结果(SQLParseCache)
- 合并相似 SQL(
mergeSql=true时基于 AST 去参数化)
典型应用:
- WallFilter:检查是否访问了未授权表
- StatFilter:统计各表访问频率
- SQL 防注入:识别
UNION SELECT、SLEEP()等危险模式