← Назад к вопросам
Что нагружается в базе данных, если соединение не закрыто и запросы не отправлены
1.0 Junior🔥 171 комментариев
#Soft Skills и карьера
Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI23 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Проблемы с незакрытыми соединениями в базе данных
Это критическая проблема, которая приводит к полной неработоспособности приложения. Сегда можно использовать connection pooling.
Что происходит в БД
Незакрытое соединение удерживает ресурсы:
- Memory — каждое соединение требует памяти
- File descriptors — операционная система имеет лимит
- Lock на таблицы — открытая транзакция удерживает блокировки
- Сессия БД — требует системных ресурсов
// Антипаттерн: подключение не закрывается
public class BadDatabaseExample {
public List<User> getAllUsers() {
Connection connection = DriverManager.getConnection(url, user, password);
Statement stmt = connection.createStatement();
ResultSet rs = stmt.executeQuery("SELECT * FROM users");
List<User> users = new ArrayList<>();
while (rs.next()) {
users.add(new User(rs.getString("name")));
}
// БД: соединение остаётся открытым!
return users;
}
}
Исчерпание ресурсов (Resource Exhaustion)
Что падает первым:
// 1. Connection Pool исчерпывается
// Pool max size: 20 соединений
// Открыто: 20 соединений (все занято)
// Новый запрос: ждёт 30 сек → timeout → ошибка
// 2. File descriptors заканчиваются
// Linux: ulimit -n (обычно 1024)
// После 1000 соединений: "Too many open files"
// 3. Память БД полностью заполняется
// shared_buffers, effective_cache_size
// БД становится медленной, затем падает
Симптомы проблемы
В логах приложения:
java.sql.SQLException: Cannot get a connection, pool max size is 20
at com.zaxxer.hikari.HikariPool.throwPoolInitializationException
at com.zaxxer.hikari.HikariPool.createConnection
ConnectionTimeoutException: Unable to acquire connection from pool
В БД (PostgreSQL):
-- Просмотр открытых соединений
SELECT count(*) FROM pg_stat_activity;
-- Результат: 500 соединений! (normal: 10-20)
-- Кто открыл эти соединения
SELECT pid, state, query FROM pg_stat_activity
WHERE state != 'idle' LIMIT 20;
-- Убийство зависших соединений
SELECT pg_terminate_backend(pid)
FROM pg_stat_activity
WHERE state = 'idle' AND query_start < now() - interval '1 hour';
Правильное управление соединениями
Используем try-with-resources (Java 7+):
public class GoodDatabaseExample {
public List<User> getAllUsers() {
try (Connection connection = DriverManager.getConnection(url, user, password);
Statement stmt = connection.createStatement();
ResultSet rs = stmt.executeQuery("SELECT * FROM users")) {
List<User> users = new ArrayList<>();
while (rs.next()) {
users.add(new User(rs.getString("name")));
}
// Автоматическое закрытие всех ресурсов
return users;
} catch (SQLException e) {
throw new RuntimeException("Database error", e);
}
}
}
Используем Connection Pool (HikariCP в Spring Boot):
@Configuration
public class DataSourceConfig {
@Bean
public DataSource dataSource() {
HikariConfig config = new HikariConfig();
config.setJdbcUrl(dbUrl);
config.setUsername(dbUser);
config.setPassword(dbPassword);
config.setMaximumPoolSize(20); // Макс соединений
config.setMinimumIdle(5); // Мин соединений
config.setConnectionTimeout(10000); // Timeout 10 сек
config.setIdleTimeout(600000); // 10 мин idle
config.setMaxLifetime(1800000); // 30 мин жизни
return new HikariDataSource(config);
}
}
В Spring Data JPA:
@Repository
public interface UserRepository extends JpaRepository<User, Long> {
// Spring автоматически управляет соединениями
@Query("SELECT u FROM User u WHERE u.name = ?1")
User findByName(String name); // Соединение закроется автоматически
}
Проблема с неотправленными запросами
Если запросы не отправлены:
// Антипаттерн: запрос подготовлен, но не выполнен
public void badExample() {
try (Connection connection = getConnection()) {
PreparedStatement stmt = connection.prepareStatement(
"SELECT * FROM users WHERE id = ?"
);
stmt.setInt(1, 123);
// stmt.executeQuery(); // ← Забыли вызвать!
// Соединение ждёт, пока будет выполнена операция
}
}
Что происходит:
- Транзакция остаётся открытой
- Блокировки не отпускаются
- Другие операции ждут этой блокировки
- Deadlock или timeout
Мониторинг и профилактика
Метрики для мониторинга:
@Configuration
public class MonitoringConfig {
@Bean
public MeterRegistry meterRegistry() {
MeterRegistry registry = new SimpleMeterRegistry();
// Количество активных соединений
Gauge.builder("db.active.connections",
() -> dataSource.getHikariPoolMXBean().getActiveConnections())
.register(registry);
// Ожидающие в очереди
Gauge.builder("db.pending.connections",
() -> dataSource.getHikariPoolMXBean().getPendingThreads())
.register(registry);
return registry;
}
}
Алерты:
ALERT: db.pending.connections > 5
→ Скоро будет exhaustion pool
ALERT: db.active.connections = max
→ Срочно нужно найти утечку
Поиск утечки соединений
// Профилирование соединений
try (Connection conn = dataSource.getConnection()) {
System.out.println("Acquired connection: " + conn);
// Используем соединение
} // Автоматически освобождается
Чтобы найти утечку:
- Включить DEBUG логирование в HikariCP
- Просмотреть stack traces открытых соединений
- Найти место, где забыли закрыть
- Исправить на try-with-resources