1. 简介
在本教程中,我们将讨论P6Spy,这是一个开源的免费库,可用于拦截Java应用程序中的SQL日志。
在本文的第一部分,我们将讨论依赖这个外部库而不是仅仅为JPA或Hibernate启用SQL日志记录的主要优势,以及我们可以将该库集成到我们的应用程序中的不同方式。然后我们将展示一个使用P6Spy的Spring Boot应用程序的简单示例,以查看一些最重要的可用配置。
2. P6Spy安装
P6Spy需要安装在应用服务器上。通常,将应用程序JAR放在类路径中并方便地配置驱动程序和JDBC连接就足够了。
使用P6Spy的另一种方法是通过与我们应用程序的现有代码集成,假设对代码进行小的更改是可以接受的。在下一节中,我们将看到一个示例,说明如何通过自动配置将P6Spy集成到Spring Boot应用程序中。
p6spy-spring-boot-starter是一个Spring Boot启动器,提供与P6Spy和其他数据库监控库的集成。多亏了这个库,启用P6Spy日志记录就像在类路径上添加一个jar一样简单。使用Maven,只需在POM.xml中添加以下代码片段:
<dependency>
<groupId>com.github.gavlyukovskiy</groupId>
<artifactId>p6spy-spring-boot-starter</artifactId>
<version>1.9.0</version>
</dependency>
如果我们要配置日志记录,我们需要在资源文件夹中添加一个名为“spy.properties”的文件:
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. 日志示例
要查看日志记录,我们需要运行一些查询。让我们向我们的应用程序添加几个简单的端点:
@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访问这些端点:
curl http://localhost:8080/student/save
curl http://localhost:8080/student/find/Pablo
我们现在可以看到在项目目录中创建了一个名为“database.log”的文件,其内容如下:
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并手动管理提交和回滚,日志记录也将起作用。让我们在应用程序中添加另一个控制器来测试此行为:
@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请求访问了以下端点:
curl http://localhost:8080/jdbc/commit
curl http://localhost:8080/jdbc/rollback
curl http://localhost:8080/jdbc/query-error
结果,我们将在“database.log”文件中看到以下日志:
1683448381083|0|statement|SELECT * FROM student
1683448381087|0|commit|
1683448386586|0|rollback|
1683448388604|3|statement|SELECT UNDEFINED()
4. 总结
在本文中,我们看到了依赖外部第三方库(例如P6Spy)来记录数据库查询的多种优势。例如,我们尝试过的特殊配置使我们摆脱了嘈杂的邻居问题(想象一下充满查询的日志控制台)。
与往常一样,本教程的完整源代码可在GitHub上获得。