使用 P6Spy 拦截 SQL日志

2023-05-19 15:38:24 浏览数 (1)

1. 简介

在本教程中,我们将讨论P6Spy,这是一个开源免费的库,用于拦截 Java 应用程序中的 SQL 日志

在文章的第一部分,我们将讨论依赖于这个外部库而不仅仅启用 JPA 或Hibernate 的 SQL 日志记录的主要优势,以及将该库集成到我们的应用程序中的不同方式。然后,我们将演示一个简单的Spring Boot应用程序示例,展示一些最重要的可配置项。

2. 安装P6Spy

P6Spy需要安装在应用服务器上。通常情况下,只需将应用程序的 JAR 放在类路径中,并方便地配置驱动程序和 JDBC 连接即可。

使用 P6Spy 的另一种方式是通过与我们应用程序的现有代码集成,假设对代码进行小的更改是可以接受的。在下一节中,我们将看到一个示例,介绍如何在 Spring Boot 应用程序中通过自动配置来集成 P6Spy。

p6spy-spring-boot-starter 是一个提供与P6Spy和其他数据库监控库集成的仓库。借助这个库,启用P6Spy日志记录就像在类路径中添加一个_jar_那样简单。使用Maven,只需在_POM.xml_中添加以下代码片段:

代码语言:javascript复制
<dependency>
    <groupId>com.github.gavlyukovskiygroupId>
    <artifactId>p6spy-spring-boot-starterartifactId>
    <version>1.9.0version>
dependency>

如果我们想要配置日志记录,需要在资源文件夹中添加一个名为_“spy.properties”_的文件:

代码语言:javascript复制
appender=com.p6spy.engine.spy.appender.FileLogger
logfile=database.log
append=true
logMessageFormat=com.p6spy.engine.spy.appender.CustomLineFormat
customLogMessageFormat=%(currentTime)|%(executionTime)|%(category)|%(sqlSingleLine)

在这种情况下,我们已经配置 P6Spy 以自定义格式将信息记录到一个名为_“database.log”_的文件中,并以追加模式进行记录。这只是一些配置中的例子,其他配置可以在项目网站上找到。

3. 日志示例

要查看日志记录,我们需要运行一些查询。让我们在应用程序中添加一些简单的端点:

代码语言:javascript复制
@RestController
@RequestMapping("student")
public class StudentController {
    @Autowired
    private StudentRepository repository;
    @RequestMapping("/save")
    public Long save() {
        return repository.save(new Student("Pablo", "Picasso")).getId();
    }
    @RequestMapping("/find/{name}")
    public List<Student> getAll(@PathVariable String name) {
        return repository.findAllByFirstName(name);
    }
}

假设应用程序暴露在端口8080上,现在让我们使用 CURL 命令访问这些端点:

代码语言:javascript复制
curl http://localhost:8080/student/save
curl http://localhost:8080/student/find/Pablo

现在我们可以看到在项目目录中创建了一个名为“database.log”的文件,其内容如下:

代码语言:javascript复制
1683396972301|0|statement|select next value for student_seq
1683396972318|0|statement|insert into student (first_name, last_name, id) values ('Pablo', 'Picasso', 1)
1683396972320|0|commit|
1683396990989|0|statement|select s1_0.id,s1_0.first_name,s1_0.last_name from student s1_0 where s1_0.first_name='Pablo'

如果我们使用_PreparedStatements_并手动管理_commits_和_rollbacks_,日志记录也会生效。让我们在应用程序中添加另一个控制器来测试这种行为:

代码语言:javascript复制
@RestController
@RequestMapping("jdbc")
public class JDBCController {
    @Autowired
    private DataSource dataSource;

    @RequestMapping("/commit")
    public List<Map<String, String>> select() {
        List<Map<String, String>> results = new ArrayList<>();
        try {
            Connection connection = dataSource.getConnection();
            Statement statement = connection.createStatement();
            statement.executeQuery("SELECT * FROM student");
        } catch (Exception e) {
            throw new IllegalStateException(e);
        }
        return results;
    }

    @RequestMapping("/rollback")
    public List<Map<String, String>> rollback() {
        List<Map<String, String>> results = new ArrayList<>();
        try (Connection connection = dataSource.getConnection()) {
            connection.rollback();
        } catch (Exception e) {
            throw new IllegalStateException(e);
        }
        return results;
    }

    @RequestMapping("/query-error")
    public void error() {
        try (Connection connection = dataSource.getConnection();
             Statement statement = connection.createStatement()) {
            statement.execute("SELECT UNDEFINED()");
        } catch (Exception ignored) {
        }
    }
}

然后,相应地使用curl请求访问以下端点:

代码语言:javascript复制
curl http://localhost:8080/jdbc/commit
curl http://localhost:8080/jdbc/rollback
curl http://localhost:8080/jdbc/query-error

结果,我们将在“database.log”文件中看到添加的以下日志:

代码语言:javascript复制
1683448381083|0|statement|SELECT * FROM student
1683448381087|0|commit|
1683448386586|0|rollback|
1683448388604|3|statement|SELECT UNDEFINED()

4. 结论

在本文中,我们已经看到了依赖于 P6Spy 等外部第三方库来记录数据库查询的多个优点。 例如,我们尝试的特殊配置可以解决嘈杂邻居问题(想象一下日志控制台充满了查询)。

代码可以在GitHub上找到。

0 人点赞