Сценарий:
Выполнено несколько повторяющихся вставок в одну и ту же таблицу. (file_record_v2, уникальный file_id) с буфером в 2–3 минуты между каждым запросом.
Код: Выделить всё
INSERT INTO file_record_v2
(iso_country_code,
created_at,
modified_at,
bucket,
file_id,
file_key,
file_name,
path,
status,
upload_date,
uploaded_by)
VALUES ('IN',
'2025-10-01 17:22:39.867',
'2025-10-01 17:22:39.867',
'Fo/89NveRaWnfjgvfsmrIE5ca7kQ2LkqvV9AKTmn0Qw=',
'777a7379-6c96-35d1-b47e-17b1708258f5',
'abcdef',
'1759316708189.csv',
NULL,
'success',
'2025-10-01',
'admin@gmail.com');
Первая вставка завершилась успешно.
2-й запрос мгновенно выдает исключение - java.sql.SQLIntegrityConstraintViolationException: Повторяющаяся запись....
После этого все последующие вставки перешли в состояние ожидания на все 50 секунд (
Код: Выделить всё
innodb_lock_wait_timeoutМедленные журналы MySQL:
Код: Выделить всё
> User@Host: admin[admin] @ [xx.xxx.xx.216] thread_id: 3225252 server_id: 2921685337
> Query_time: 50.939886 Lock_time: 50.939609 Rows_sent: 0 Rows_examined: 0 use
> shard0; SET timestamp=1759319339; insert into file_record_v2
> (iso_country_code, created_at, modified_at, bucket, file_id, file_key,
> file_name, path, status, upload_date, uploaded_by) values ('IN',
> '2025-10-01 17:18:59.548', '2025-10-01 17:18:59.548',
> 'Fo/89NveRaWnfjgvfsmrIE5ca7kQ2LkqvV9AKTmn0Qw=',
> '777a7379-6c96-35d1-b47e-17b1708258f5', 'abcdef', '1759316708189.csv',
> null, 'success', '2025-10-01', 'admin@gmail.com');

После 50 секунд MySQL ограничивает время ожидания запросов, но Хикари не возвращает эти соединения в пул.
В конце концов, все 5 соединений в пуле исчерпаны, и приложение начало выдавать:
Ошибка:
java.sql.SQLTransientConnectionException: HikariPool-1 — соединение недоступно...

Фрагмент кода
Код: Выделить всё
@Override
public FileUploadResponse storeFileMetadata(String bucketName, String fileKey, String fileName, String user, String countryCode) throws Exception {
String fileId = // create file id;
LocalDateTime localDateTime = getLocalDateTime();
try {
// Build entity
FileRecordEntity entity = FileRecordEntity.builder()
.fileId(fileId)
.fileName(fileName)
.uploadDate(getDate())
.bucket(bucketName)
.fileKey(fileKey)
.userId(user)
.status(FileStatus.SUCCESS.getValue())
.countryCode(countryCode)
.createdAt(localDateTime)
.modifiedAt(localDateTime)
.build();
fileRecordRepository.save(entity); // Only DB query which got latent
return new FileUploadResponse(fileId, null);
} catch (ConstraintViolationException | DataIntegrityViolationException e) {
log.error(e.getMessage(), e);
if (StringUtils.containsIgnoreCase(e.getCause().getCause().getMessage(), "Duplicate entry"))
throw new FileValidationException(String.format("Duplicate file: %s", fileName));
throw e;
}
}
Мы восстановились после перезапуска приложения, чтобы освободить исчерпанный пул.
Версия:
Код: Выделить всё
Spring Boot: 2.7.10
Spring Data JPA: 2.7.10
HikariCP: 4.0.3
Hibernate: 5.6.15.Final
Driver : com.mysql.cj.jdbc.Driver
Код: Выделить всё
driverClassName: com.mysql.cj.jdbc.Driver
idleTimeout: '600000'
initializationFailTimeout: '1'
maxLifetime: '3600000'
maximumPoolSize: '5'
minIdle: '1'
validationQuery: SELECT 1
Вопрос. Утечка соединения: почему HikariCP не освобождает соединения после того, как MySQL истечет время выполнения запроса (как видно из медленных журналов сразу после 50 секунд), и как я могу принудительно закрыть такие соединения автоматически?
Схема БД:
Одна проблема, которую мы наблюдали в таблице ниже, заключается в том, что столбец с именем file_id имеет 2 уникальных и 1 неуникальный индекс, который может быть причиной медленных вставок дубликатов, таких как блокировка нескольких индексов ~ 50 секунд (но все равно кажется слишком большим для обновления строки с 4 индексами), кажется, что где-то здесь происходит взаимная блокировка (причина в том, что все запросы начались, но ни один запрос не был заблокирован, и все они были завершены после тайм-аута блокировки inno_db) здесь вызывает ожидание в течение 50 секунд для получения блокировки, но это все еще не объясняет частично, почему соединение на стороне приложения не было освобождено после 50 секунд, и либо зависло в бесконечном ожидании, либо где-то произошла утечка соединения.

Подробнее здесь: https://stackoverflow.com/questions/797 ... rt-queries
Мобильная версия