由于复杂sql篇幅比较长,这里就随意执行一串比较简单的sql作为代表,怎么去实现较为精准的异常sql定位,帮助各位开发小伙伴解决问题
ps:文章末尾有解决该异常的彩蛋,能让开发更顺畅哟
相关驱动前置说明
<!-- postgresql jdbc 驱动包 -->
<!-- https://mvnrepository.com/artifact/org.postgresql/postgresql -->
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<version>42.2.24</version>
</dependency>
<!-- druid jdbc连接池 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.21</version>
</dependency>
执行sql如下:
// 随意编写的一句sql
String sql = "select * from cr_vehicle_type " +
"where VEHICLE_TYPE_ID in(?,200) " +
" and create_time > ? ";
// create_time 字段故意传入时间字符串,pg会报错,mysql是不会的
EDb.use("pg").find(VehicleType.class,sql,100, "2020-01-08");
异常信息如下:
com.jfinal.plugin.activerecord.ActiveRecordException: java.lang.RuntimeException: org.postgresql.util.PSQLException: ERROR: operator does not exist: timestamp without time zone > character varying
建议:No operator matches the given name and argument types. You might need to add explicit type casts.
位置:81
at com.edbplus.db.EDbPro.find(EDbPro.java:1144)
如果是以上异常信息提示的话,我们很难去定位到 create_time 字段的类型有异,简单的sql还好,复杂的sql有好多字段,光凭 【位置:81】 和 【ERROR: operator does not exist: timestamp without time zone > character varying】 等关键字眼,对开发人员来说,实在太难了
所以建议结合druid进行相关简单的改造
继承 FilterEventAdapter 实现sql上下游动作的相关监听
public class EDbDruidSqlLogFilter extends FilterEventAdapter{
...
...
/**
* druid自带的sql异常之上下游监听 -> 执行sql报错之后触发
* @param statement
* @param sql
* @param error
*/
@Override
protected void statement_executeErrorAfter(StatementProxy statement, String sql, Throwable error) {
try{
if(error.getMessage().contains("位置")){
String errStr = error.getMessage();
// 提取 【位置:81】 里的数字,便于结合sql语句进行精准范围定位
int idx = ReUtil.getFirstNumber(errStr.substring(errStr.indexOf("位置")));
int startIdx,endIdx =0;
if((idx - 20)>0){
startIdx = idx - 20;
}else{
startIdx = 0;
}
if((idx + 10)<sql.length()){
endIdx = idx + 10;
}else{
endIdx = sql.length();
}
// 弥补pgsql打印时,无法精准输出异常字段的问题
String errMsg = "sql异常位置:" + sql.substring(startIdx,endIdx) ;
log.error(errMsg);
}
}catch (Throwable e)
{
log.error(e);
}
}
}
结果如下
如上图所示,我们就可以通过 【sql异常位置: and create_time > ?】的提示并结合【ERROR: operator does not exist: timestamp without time zone > character varying】,非常方便定位到异常信息和问题,能很快的发现问题并修复该异常,节省大量的测试时间和结构性差异对比
ps:其实解决格式化异常最好的方式是数据库驱动自己兼容实现:
stringtype=unspecified -> 格式化参数即可
-- 连接示例参考:
jdbc:postgresql://192.168.1.11:5432/pg_test?currentSchema=public&reWriteBatchedInserts=true&TimeZone=Asia/Shanghai&useUnicode=true&characterEncoding=utf8&stringtype=unspecified