Cách tốt nhất để tackle connection leaks is to do it during testing.
Bạn có thể sử dụng tiện ích tự động để mỗi thử nghiệm xác minh xem có rò rỉ kết nối hay không.
@BeforeClass
public static void initConnectionLeakUtility() {
if (enableConnectionLeakDetection) {
connectionLeakUtil = new ConnectionLeakUtil();
}
}
@AfterClass
public static void assertNoLeaks() {
if (enableConnectionLeakDetection) {
connectionLeakUtil.assertNoLeaks();
}
}
Các ConnectionLeakUtil
trông như thế này:
public class ConnectionLeakUtil {
private JdbcProperties jdbcProperties = JdbcProperties.INSTANCE;
private List idleConnectionCounters =
Arrays.asList(
H2IdleConnectionCounter.INSTANCE,
OracleIdleConnectionCounter.INSTANCE,
PostgreSQLIdleConnectionCounter.INSTANCE,
MySQLIdleConnectionCounter.INSTANCE
);
private IdleConnectionCounter connectionCounter;
private int connectionLeakCount;
public ConnectionLeakUtil() {
for (IdleConnectionCounter connectionCounter :
idleConnectionCounters) {
if (connectionCounter.appliesTo(
Dialect.getDialect().getClass())) {
this.connectionCounter = connectionCounter;
break;
}
}
if (connectionCounter != null) {
connectionLeakCount = countConnectionLeaks();
}
}
public void assertNoLeaks() {
if (connectionCounter != null) {
int currentConnectionLeakCount = countConnectionLeaks();
int diff = currentConnectionLeakCount - connectionLeakCount;
if (diff > 0) {
throw new ConnectionLeakException(
String.format(
"%d connection(s) have been leaked! Previous leak count: %d, Current leak count: %d",
diff,
connectionLeakCount,
currentConnectionLeakCount
)
);
}
}
}
private int countConnectionLeaks() {
try (Connection connection = newConnection()) {
return connectionCounter.count(connection);
}
catch (SQLException e) {
throw new IllegalStateException(e);
}
}
private Connection newConnection() {
try {
return DriverManager.getConnection(
jdbcProperties.getUrl(),
jdbcProperties.getUser(),
jdbcProperties.getPassword()
);
}
catch (SQLException e) {
throw new IllegalStateException(e);
}
}
}
Các IdleConnectionCounter
triển khai có thể được tìm thấy trong blog post này, và phiên bản MySQL như thế này:
public class MySQLIdleConnectionCounter implements IdleConnectionCounter {
public static final IdleConnectionCounter INSTANCE =
new MySQLIdleConnectionCounter();
@Override
public boolean appliesTo(Class<? extends Dialect> dialect) {
return MySQL5Dialect.class.isAssignableFrom(dialect);
}
@Override
public int count(Connection connection) {
try (Statement statement = connection.createStatement()) {
try (ResultSet resultSet = statement.executeQuery(
"SHOW PROCESSLIST")) {
int count = 0;
while (resultSet.next()) {
String state = resultSet.getString("command");
if ("sleep".equalsIgnoreCase(state)) {
count++;
}
}
return count;
}
}
catch (SQLException e) {
throw new IllegalStateException(e);
}
}
}
Bây giờ, khi bạn chạy của bạn kiểm tra, bạn sẽ gặp lỗi khi kết nối bị rò rỉ.
Nguồn
2016-07-12 13:08:44
Điều này so sánh với p6spy như thế nào? –
@ Thorbjørn Tôi coi nó như là một sự thay thế hiện đại hơn (bản phát hành mới nhất của P6Spy là 7+ năm trước): nó sử dụng SLF4J, nó cung cấp một số tính năng và tùy chọn cấu hình mà tôi thích, nó hỗ trợ JDBC 4 ... thay thế ngay bây giờ. –
ConnLeakFinder làm việc rất tốt cho tôi. Cảm ơn các liên kết. –