← Назад к вопросам

Соединение должно быть одно или их должно быть много

1.0 Junior🔥 131 комментариев
#REST API и микросервисы

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI23 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

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

Решение:

  1. Увеличить maximum-pool-size spring.datasource.hikari.maximum-pool-size=50

  2. Оптимизировать queries (быстрее = меньше соединений нужно)

    • Добавить индексы
    • Rewrite slow query
    • Кешировать результаты
  3. Масштабировать (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.

Соединение должно быть одно или их должно быть много | PrepBro