【问题标题】:Enabling MySQL general query log with JDBC使用 JDBC 启用 MySQL 通用查询日志
【发布时间】:2012-06-09 19:39:18
【问题描述】:

有没有办法通过 JDBC 启用 MySQL 常规查询日志记录?我通过搜索找到的最接近的东西是能够通过 JDBC (http://dev.mysql.com/doc/refman/5.5/en/connector-j-reference-configuration-properties.html) 记录慢速查询。也许我应该这样做并将慢查询阈值设置为 0 毫秒?

我想通过 MySQL 以人类可读的格式记录所有查询,并想指定应该写入日志文件的位置。我知道我会受到性能影响,但我的应用程序只有一个用户,而且非常简单,如果性能影响很明显,我会感到惊讶。无论如何我都想试试看。

我相信我的另一个选择是打开二进制日志记录并使用 mysqlbinlog 将二进制日志转换为人类可读的格式,但听起来通用查询日志会提供一种更简单的方法来获取我想要的内容。

【问题讨论】:

    标签: mysql logging jdbc


    【解决方案1】:

    您可以像这样在 JDBC URL 中启用日志记录:

    jdbc:mysql://host/db?logger=com.mysql.jdbc.log.Log4JLogger&profileSQL=true
    

    其他日志后端可用(CommonsLogger、Slf4jLogger、JDK14Logger)。我相信由于许可问题,在某些时候直接 Log4J 日志记录已被删除,因此它可能不适用于您的 JDBC 驱动程序版本。

    当然,您的类路径中需要相关的日志库的 JAR,以及一个配置文件 (log4j.properties)。我会先将根级别设置为 TRACE 以查看正在发生的事情,并在您看到正在记录的内容后按日志级别和类别收紧它。

    进一步阅读:

    HTH

    【讨论】:

    • 谢谢!当使用不容易支持添加日志记录参数的黑盒/闭源框架时,确实如此
    • 请注意,由于许可证不兼容,Log4JLogger 显然不再包含在 Connector/J 中,但 Slf4JLogger(具有大写 J,而不是上面建议的小写)仍然可用,并将通过 log4j 记录如果它存在。
    • 这几天日志包已经移到com.mysql.cj.log,例如com.mysql.cj.log.Slf4JLogger
    【解决方案2】:

    将“logger”和“profileSQL”添加到 jdbc url:

    &logger=com.mysql.jdbc.log.Slf4JLogger&profileSQL=true
    

    然后你会得到下面的SQL语句:

    2016-01-14 10:09:43  INFO MySQL - FETCH created: Thu Jan 14 10:09:43 CST 2016 duration: 1 connection: 19130945 statement: 999 resultset: 0
    2016-01-14 10:09:43  INFO MySQL - QUERY created: Thu Jan 14 10:09:43 CST 2016 duration: 1 connection: 19130945 statement: 999 resultset: 0 message: SET sql_mode='NO_ENGINE_SUBSTITUTION,STRICT_TRANS_TABLES'
    2016-01-14 10:09:43  INFO MySQL - FETCH created: Thu Jan 14 10:09:43 CST 2016 duration: 1 connection: 19130945 statement: 999 resultset: 0
    2016-01-14 10:09:43  INFO MySQL - QUERY created: Thu Jan 14 10:09:43 CST 2016 duration: 2 connection: 19130945 statement: 13 resultset: 17 message: select 1
    2016-01-14 10:09:43  INFO MySQL - FETCH created: Thu Jan 14 10:09:43 CST 2016 duration: 0 connection: 19130945 statement: 13 resultset: 17
    2016-01-14 10:09:43  INFO MySQL - QUERY created: Thu Jan 14 10:09:43 CST 2016 duration: 1 connection: 19130945 statement: 15 resultset: 18 message: select @@session.tx_read_only
    2016-01-14 10:09:43  INFO MySQL - FETCH created: Thu Jan 14 10:09:43 CST 2016 duration: 0 connection: 19130945 statement: 15 resultset: 18
    2016-01-14 10:09:43  INFO MySQL - QUERY created: Thu Jan 14 10:09:43 CST 2016 duration: 2 connection: 19130945 statement: 14 resultset: 0 message: update sequence set seq=seq+incr where name='demo' and seq=4602
    2016-01-14 10:09:43  INFO MySQL - FETCH created: Thu Jan 14 10:09:43 CST 2016 duration: 0 connection: 19130945 statement: 14 resultset: 0
    

    默认记录器是:

    com.mysql.jdbc.log.StandardLogger
    

    Mysql jdbc属性列表:https://dev.mysql.com/doc/connector-j/en/connector-j-reference-configuration-properties.html

    【讨论】:

    • 如果这些是您唯一的连接参数,您应该使用“?logger=com.mysql.jdbc.log.Slf4JLogger&profileSQL=true”(否则 JDBC 代码会将数据库名称与其余的行)
    • 你的类路径中需要 slf4j-api 和 slf4j-simple。
    【解决方案3】:

    如果您正在使用 Hibernate,并通过它执行所有数据访问,您可以通过将属性 hibernate.show_sql 设置为 true 来打开日志记录。不过,这将编写参数化语句(例如SELECT foo.id FROM foo WHERE foo.bar = ?)。如果您需要参数值,或者不使用 Hibernate 之类的工具,您可能需要让 MySQL 写入此日志。请参阅general query log 上的 MySQL 文档。

    FWIW,MySQL 二进制日志是达到不同目的的一种手段;它记录对数据的更改,并用于增量备份和/或复制。 SELECT 语句不会记录在二进制日志中。

    编辑: 我可以通过将以下两行添加到 my.cnf(在确认两个变量都没有设置之后)并重新启动 MySQL 来让 MySQL 写入常规日志:

    
    general_log = 1
    general_log_file=/tmp/mysql-general.log
    

    【讨论】:

    • Eric,我从来没有看过一页可以理解的 MySQL 官方文档,而且我已经使用了 5 年。我可以非常具体地指出该页面上的歧义。你能展示一个打开通用查询日志的示例查询吗?我也不知道我是否使用休眠。如果你能告诉我如何检查,我可以告诉你。
    【解决方案4】:

    我最终找到了解决方法。我通过 Java 启用 MySQL 常规查询日志记录,方法是在运行时使用以下 SQL 查询修改 MySQL 全局系统变量。

    SET GLOBAL log_output="FILE"
    SET GLOBAL general_log_file="Path/File"
    SET GLOBAL general_log='ON'
    

    我建议在 general_log_file 路径中使用正斜杠。即使在 Windows 环境中,我也无法使用反斜杠。

    我使用以下 SQL 查询在运行时禁用常规查询日志记录。

    SET GLOBAL general_log='OFF'
    

    【讨论】:

    • 看起来这会将查询记录到服务器。如果您没有对运行 MySQL 的服务器的登录访问权限,那将无济于事。
    【解决方案5】:

    使用 MySQL 和 mysql-connector-java-8.0.13.jar 我将 profileSQL=true 添加到我的 JDBC 连接 URL。例如:

    jdbc:mysql://${HOST}:${PORT}/${SCHEMA}?autoReconnect=true&profileSQL=true
    

    您也可以在 URL 中添加 &logger=com.mysql.cj.log.StandardLogger,但这不是必需的,因为它是文档中指示的默认值。

    文档参考:

    https://dev.mysql.com/doc/connector-j/8.0/en/connector-j-reference-configuration-properties.html

    日志输出读起来很烦人,因为它包含一个堆栈跟踪,指示查询在代码中的确切位置运行。如果有人想出排除堆栈跟踪的方法,请告诉我。

    【讨论】:

    • StandardLogger 是默认的,你可以省略它。第一个参数需要一个?而不是 & 与任何 URI 一样。
    • 但仍然对我不起作用。从com.mysql.cj.util.LogUtils.expandProfilerEventIfNecessary(LogUtils.java:53) 引发错误。有什么想法吗?
    • 这是我在回答中谈到的堆栈跟踪的一部分。如果您深入查看堆栈跟踪,它会告诉您查询是在哪一行代码中执行的。我只是再次尝试并最初认为有问题,但我的应用程序仍然运行,它仍然输出正在运行的查询。如果有一个解决方案可以省略堆栈跟踪,那将是理想的。
    【解决方案6】:

    对于 Spring Boot 的最新 MySQL 驱动程序版本,请添加 JDBC 连接 URL:

    spring.datasource.url: jdbc:mysql://localhost:49172/INTEGRATION_DB?logger=com.mysql.cj.log.Slf4JLogger&profileSQL=true
    

    它将使用 Slf4J 记录器。如果没有这样的记录器,可以使用标准记录器:logger=com.mysql.cj.log.StandardLogger

    也可以使用自定义记录器,只需实现接口com.mysql.cj.log.Log并在连接URL中指定一个新记录器。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-12-25
      • 1970-01-01
      • 2011-09-22
      • 2014-05-01
      • 1970-01-01
      • 2014-05-08
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多