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上找到。