Соединение должно быть одно или их должно быть много
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Database Connection Pool: Одно или много?
Ответ: МНОГО, но контролировано
Не одно глобальное соединение, а пул из 5-50 соединений в зависимости от нагрузки.
Почему не одно?
❌ Плохо: одно соединение
Connection conn = DriverManager.getConnection(url, user, pass);
// Запрос 1 (100ms)
statement1.execute(sql1);
// Запрос 2 (100ms)
statement2.execute(sql2); // Ждёт, пока Запрос 1 завершится!
// Запрос 3 (100ms)
statement3.execute(sql3); // Ждёт в очереди
// Результат: 300ms для 3 параллельных запросов!
✅ Хорошо: пул из 10 соединений
Connections = [conn1, conn2, ..., conn10]
// Запрос 1 → conn1 (100ms)
// Запрос 2 → conn2 (100ms в параллели)
// Запрос 3 → conn3 (100ms в параллели)
// Результат: ~100ms для 3 параллельных запросов! (3x быстрее)
Connection Pool в Spring Boot
HikariCP (default в Spring Boot)
spring: datasource:
hikari:
maximum-pool-size: 20 # Максимум 20 соединений
minimum-idle: 5 # Минимум 5 (всегда готовых)
connection-timeout: 30000 # 30 сек ждём соединение
idle-timeout: 10 # 10 мин закрыть неиспользуемые
max-lifetime: 30 # 30 мин макс жизнь соединения
Как это работает
При старте ApplicationContext:
┌─────────────────────────────────┐
│ HikariCP Pool │
├─────────────────────────────────┤
│ [conn1] [conn2] [conn3] [conn4] │
│ [conn5] [WAITING...] [...] │
│ Active: 3, Idle: 2, Waiting: 5 │
└─────────────────────────────────┘
Когда приходит Request 1:
└─ Берём свободное соединение: conn1
Выполняем query: SELECT * FROM users
Возвращаем соединение в пул когда done
Когда приходит Request 2 одновременно:
└─ Берём другое свободное: conn2
Выполняем query параллельно
Оптимальный размер пула
Правило: (Количество ядер * 2) + Резерв
4-ядерная машина:
- Optimal: 4 * 2 + 3 = 11 соединений
- MIN: 5-10
- MAX: 20
8-ядерная машина:
- Optimal: 8 * 2 + 3 = 19 соединений
- MIN: 10
- MAX: 30
16-ядерная машина:
- Optimal: 16 * 2 + 3 = 35 соединений
- MIN: 20
- MAX: 50
Практический пример
// Service
@Service
public class UserService {
private final JdbcTemplate jdbcTemplate;
// JdbcTemplate автоматически берёт соединение из пула
public User getUser(Long id) {
return jdbcTemplate.queryForObject(
"SELECT * FROM users WHERE id = ?",
new Object[]{id},
User.class
);
// Соединение автоматически возвращается в пул
}
}
// Spring автоматически управляет pool через Hikari
// Мы не должны думать о соединениях!
Когда пула недостаточно
Симптомы:
- ERROR: cannot get a connection, pool error
- Connection timeout exceptions
- Application slow response
Решение:
-
Увеличить maximum-pool-size spring.datasource.hikari.maximum-pool-size=50
-
Оптимизировать queries (быстрее = меньше соединений нужно)
- Добавить индексы
- Rewrite slow query
- Кешировать результаты
-
Масштабировать (horizontal)
- Несколько инстансов приложения
- Каждый имеет свой пул
Мониторинг пула
@Component
public class PoolMonitor {
@Autowired
private DataSource dataSource;
@Scheduled(fixedRate = 60000)
public void monitorPool() {
HikariDataSource hds = (HikariDataSource) dataSource;
int active = hds.getHikariPoolMXBean().getActiveConnections();
int idle = hds.getHikariPoolMXBean().getIdleConnections();
logger.info("Pool - Active: {}, Idle: {}", active, idle);
if (active > 15) {
logger.warn("High pool usage detected!");
}
}
}
Connection Leaks
❌ Плохо: соединение не возвращается в пул
Connection conn = dataSource.getConnection(); try {
stmt.execute(sql);
} catch (Exception e) {
// Забыли закрыть соединение!
logger.error("Error", e);
}
// Результат: соединение stuck в пуле, потом пул пусто
✅ Правильно: используй try-with-resources
try (Connection conn = dataSource.getConnection();
Statement stmt = conn.createStatement()) {
stmt.execute(sql);
} catch (Exception e) {
logger.error("Error", e);
}
// Соединение автоматически закроется и вернётся в пул
✅ Или используй Spring Template
jdbcTemplate.query(sql, resultSet -> {
// Spring управляет соединением
});
Одно vs Много итоговое резюме
| Аспект | Одно соединение | Пул соединений |
|---|---|---|
| Параллелизм | Последовательное выполнение | Истинно параллельные |
| Performance | Медленно (100ms * N) | Быстро (~100ms) |
| Memory | Минимальная | Оптимальная |
| Масштабируемость | Нет | Да, хорошая |
| Complexity | Просто | HikariCP делает всё |
Вывод: МНОГО соединений в пуле — это правильно и единственный способ для production.