如何将JDBI @SqlCall调用的存储过程中print语句输出到Java应用日志?
解决Micronaut+JDBI捕获SQL Server存储过程PRINT输出的问题
核心原理
SQL Server的PRINT语句输出会被JDBC驱动封装为SQLWarning返回(而非结果集),只要在JDBI执行流程中加入逻辑提取这些警告,就能将其记录到应用日志里。
实现步骤
1. 编写JDBI语句拦截器
利用JDBI的StatementInterceptor接口,在存储过程执行后提取并记录警告:
import org.jdbi.v3.core.statement.StatementContext; import org.jdbi.v3.core.statement.StatementInterceptor; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.sql.SQLException; import java.sql.SQLWarning; import java.sql.Statement; public class SqlServerPrintLogger implements StatementInterceptor { private static final Logger LOG = LoggerFactory.getLogger(SqlServerPrintLogger.class); @Override public void afterExecution(Statement stmt, StatementContext ctx) throws SQLException { SQLWarning warning = stmt.getWarnings(); // 遍历所有警告,SQL Server的PRINT输出对应SQL状态码01000 while (warning != null) { if ("01000".equals(warning.getSQLState())) { LOG.debug("存储过程PRINT输出: {}", warning.getMessage()); } warning = warning.getNextWarning(); } // 清除警告,避免后续语句重复处理 stmt.clearWarnings(); } }
2. 在Micronaut中注册拦截器
通过配置工厂类,将自定义拦截器绑定到JDBI实例:
import io.micronaut.context.annotation.Bean; import io.micronaut.context.annotation.Factory; import org.jdbi.v3.core.Jdbi; import javax.sql.DataSource; @Factory public class JdbiConfiguration { @Bean public Jdbi jdbi(DataSource dataSource) { Jdbi jdbi = Jdbi.create(dataSource); // 注册PRINT日志拦截器 jdbi.registerStatementInterceptor(new SqlServerPrintLogger()); return jdbi; } }
3. 正常调用存储过程
使用@SqlCall注解调用存储过程时,拦截器会自动捕获PRINT输出并记录:
import org.jdbi.v3.sqlobject.customizer.Bind; import org.jdbi.v3.sqlobject.statement.SqlCall; public interface LegacyProcDao { @SqlCall("{call Legacy_Proc_Name(:inputParam)}") void executeLegacyProc(@Bind("inputParam") String input); }
注意事项
- 确保使用的SQL Server JDBC驱动(
com.microsoft.sqlserver:mssql-jdbc)为稳定新版本,旧版本可能存在PRINT输出处理差异。 - 调整日志级别为
DEBUG(或对应级别)才能看到输出,若需要更醒目可改为LOG.info()。 - 该逻辑不影响存储过程结果集的正常处理,仅额外捕获PRINT输出。
内容的提问来源于stack exchange,提问作者maborg
相关产品推荐
相关产品推荐

