dblink查询超时后如何让PostgreSQL存储过程继续循环执行
解决dblink查询超时后继续循环的问题
核心问题
常规when others捕获逻辑无法妥善处理dblink超时对应的SQL state: 57014异常,且超时后dblink连接会进入无效状态,若不主动清理会阻断后续循环执行。
修改后的代码实现
for rec in (select dbc.db_name, dbc.con_string || ' options = ''-c statement_timeout='||_queryTimeout*1000||''' ' as con_string from db_connections dbc ) LOOP exceptionMsg := ''; raise notice '% start', rec.db_name ; BEGIN PERFORM dblink_connect(rec.db_name, rec.con_string); insert into results_tbl (db_name, value, query_text) select rec.db_name, value, _queryText from dblink(rec.db_name, format($query$ select json_agg(x.*)::text from (%1$s)x $query$, _queryText ) ) r (value text); PERFORM dblink_disconnect(rec.db_name); EXCEPTION -- 专门捕获statement timeout异常(SQLSTATE 57014) WHEN SQLSTATE '57014' THEN GET STACKED DIAGNOSTICS exceptionMsg = message_text; RAISE NOTICE ' ******TIMEOUT EXCEPTION******* Database: % Message: % **************', rec.db_name, exceptionMsg; -- 强制断开无效连接 PERFORM dblink_disconnect(rec.db_name); -- 捕获其他所有异常 WHEN OTHERS THEN GET STACKED DIAGNOSTICS exceptionMsg = message_text; RAISE NOTICE ' ******GENERAL EXCEPTION******* Database: % Message: % **************', rec.db_name, exceptionMsg; -- 清理异常连接 PERFORM dblink_disconnect(rec.db_name); END; COMMIT; raise notice '% done', rec.db_name ; END LOOP;
关键修改点
- 精准捕获超时异常:单独指定
SQLSTATE '57014'捕获超时场景,日志信息更清晰。 - 强制清理无效连接:无论执行成功还是异常(含超时),都确保执行
dblink_disconnect,避免无效连接占用资源或阻断后续操作。 - 调整代码结构:将
dblink_connect移入内部事务块,确保连接失败时也能进入异常处理逻辑,避免连接泄露。 - 增强日志定位:在通知中加入数据库名称,快速定位异常来源库。
兼容旧版本补充
若使用的PostgreSQL版本较旧,dblink_disconnect在无效连接上执行可能抛出新异常,可嵌套小事务块处理:
BEGIN PERFORM dblink_disconnect(rec.db_name); EXCEPTION WHEN OTHERS THEN RAISE NOTICE 'Failed to disconnect from %: %', rec.db_name, SQLERRM; END;
内容的提问来源于stack exchange,提问作者sh4rkyy
相关产品推荐
相关产品推荐

