1. 需求
使用Druid连接池工具格式化sql用于回显时候美观展示
2. 代码示例
2.1 依赖
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.2.6</version>
</dependency>
2.2 ParseUtils
import com.alibaba.druid.DbType;
import com.alibaba.druid.sql.ast.SQLStatement;
import com.alibaba.druid.sql.dialect.postgresql.visitor.PGOutputVisitor;
import com.alibaba.druid.sql.parser.SQLParserUtils;
import com.alibaba.druid.sql.parser.SQLStatementParser;
import com.alibaba.druid.sql.visitor.SQLASTOutputVisitor;
import java.util.List;
/**
* @author pp_lan
* @date 2024/1/15
*/
public class ParseUtils {
private ParseUtils() {
}
public static String format(String sql, String dbTypeStr) {
DbType dbType = DbType.of(dbTypeStr);
if (dbType == null) {
throw new RuntimeException("不支持的数据库类型");
}
List<SQLStatement> statementList = toStatementList(sql, dbType);
String result = sqlToString(statementList, dbTypeStr, null);
return result;
}
public static List<SQLStatement> toStatementList(String sql, DbType dbType) {
SQLStatementParser parser = SQLParserUtils.createSQLStatementParser(sql, dbType);
return parser.parseStatementList();
}
public static String sqlToString(List<SQLStatement> statementList, String dbType, List<Object> parameters) {
StringBuilder sb = new StringBuilder();
SQLASTOutputVisitor visitor;
switch (dbType) {
case "postgresql":
visitor = new PGOutputVisitor(sb);
break;
case "mysql":
visitor = new MySqlOutputVisitor(sb);
break;
default:
visitor = new SQLASTOutputVisitor(sb);
}
visitor.setParameters(parameters);
for (SQLStatement statement : statementList) {
statement.accept(visitor);
}
return sb.toString();
}
public static void main(String[] args) {
// 使用::将数值转为varchar
try {
System.out.println("[使用::转换]");
String sql = "select sum(in_use) :: varchar from t_user";
System.out.println(format(sql, DbType.postgresql.name()));
} catch (Exception e) {
System.out.println("使用::转换异常");
}
// 使用cast将数值转为varchar
try {
System.out.println("[使用cast转换]");
String newSql = "select cast(sum(in_use) as varchar) from t_user";
System.out.println(format(newSql, DbType.postgresql.name()));
} catch (Exception e) {
System.out.println("使用cast转换异常");
}
}
}
3. 运行结果
[使用::转换]
SELECT sum(in_use)::varchar
FROM t_user
[使用cast转换]
SELECT CAST(sum(in_use) AS varchar)
FROM t_user
4. 踩坑记录
4.1 描述
之前我使用的是druid为1.2.4版本,在解析pg库sql时候,发现执行结果如下:
[使用::转换]
使用::转换异常
[使用cast转换]
SELECT CAST(sum(in_use) AS varchar)
FROM t_user
可以发现,转换函数::在解析时候异常了
4.2 解决方法
切换高版本1.2.6及以上,可以正常解析。
4.3 总结
druid的1.2.6以下版本对于包含数值使用::转换为varchar的场景不支持,会导致解析报错。可以使用以下方法解决:
- 升级druid版本到1.2.6及以上
- 在格式化的方法上加上try-catch,格式化异常的时候使用原来的sql用于回显