配置

  1. 引入 maven 依赖
    1
    2
    3
    4
    5
    <dependency>  
    <groupId>p6spy</groupId>
    <artifactId>p6spy</artifactId>
    <version>${p6spy.version}</version>
    </dependency>
  2. 配置 spy.properties 文件
    1
    2
    3
    4
    5
    6
    logMessageFormat=com.xxx.P6SpyLogger  
    appender=com.p6spy.engine.spy.appender.Slf4JLogger
    dateformat=yyyy-MM-dd HH:mm:ss
    # 过滤 druid 空闲检测语句
    filter=true
    exclude=DUAL
  3. 自定义日志格式
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    public class P6SpyLogger implements MessageFormattingStrategy {  
    /**
    * @param connectionId: 连接ID
    * @param now: 当前时间
    * @param elapsed: 花费时间
    * @param category: 类别
    * @param prepared: 预编译SQL
    * @param sql: 最终执行的SQL
    * @param url: 数据库连接地址
    * @return 格式化日志结果
    */
    @Override
    public String formatMessage(int connectionId, String now, long elapsed, String category, String prepared, String sql, String url) {
    if (StrUtil.isBlank(sql) || "SELECT 1 FROM DUAL".equals(sql)) {
    return "";
    } else {
    return " took:" + elapsed + " ms" + " | sql:" + sql.replaceAll("[\\s]+", " ") + "\n";
    }
    }
    }

流程

  1. 配置 p6spy 的 mysql 驱动:com.p6spy.engine.spy.P6SpyDriver
    p6spy执行流程-1

  2. 通过 P6SpyDriver 创建 Connection,返回 com.p6spy.engine.wrapper.ConnectionWrapper 包装真正的 Connection
    p6spy执行流程-2

    p6spy执行流程-3

  3. ConnectionWrapper 重写 createStatement(),返回 com.p6spy.engine.wrapper.StatementWrapper 包装真正的 Statement
    p6spy执行流程-4

    p6spy执行流程-5

  4. StatementWrapper 重写 executeQuery(),在执行 sql 之后调用 JdbcEventListener 的 onAfterExecuteQuery()

    p6spy执行流程-6

    p6spy执行流程-7

  5. 最终执行子类 LoggingEventListener 的 onAfterAnyExecute(),调用 P6Logger 的 logSQL()
    p6spy执行流程-8

    p6spy执行流程-9

    p6spy执行流程-10