У нас есть приложение Spring, которое интегрируется с базой данных DB2 (LUW).
В указанном потоке c у нас есть метод, аннотированный @Transactional(timeout=60)
При большой нагрузке на базу данных мы заметили, что вышеупомянутый тайм-аут 60 секунд не может вызвать исключение по времени. Он делает это только тогда, когда обработка базы данных завершается либо успешно, либо с ошибкой.
Сообщения о сбоях подобны приведенным ниже:
2020-02-21 18: 45: 32,463 ОШИБКА ... Тайм-аут транзакции: крайний срок: пт 21 февраля 18:40:14 EET 2020
Обратите внимание, что исключение было выдано после освобождения ресурсов базами данных, с ошибкой тайм-аута блокировки в конкретный случай c, примерно на 5 минут позже, чем я ожидал из-за настроенного тайм-аута транзакции.
Я попытался воспроизвести это поведение, вызвав вручную задержку в базе данных. В частности, я вызываю спящую процедуру DB2 из моего приложения в течение периода, превышающего настроенное время ожидания транзакции. Мои тесты имеют тот же результат, исключение выдается только после успешного завершения операции сна.
Я хотел проверить похожий сценарий с другой базой данных, поэтому я создал простой загрузочный проект Spring с 2 различными профилями, один для DB2 и один для Postgres. Выполняя этот пример, я наблюдаю аналогичное поведение для DB2, то есть время ожидания транзакции не вызывает никаких ошибок или оно происходит только после того, как время ожидания, сконфигурированное для DB2 (30 с), которое больше настроенного времени ожидания транзакции (10 с), заканчивается.
Напротив Postgres поведение более или менее то, что я ожидал бы. Соединение с БД завершается с исключением того момента, когда истекло время ожидания транзакции (10 с), не дожидаясь, пока операция сна завершится sh (30 с).
Пример проекта: здесь . Ниже приведен пример того, что описано здесь:
package com.example.demo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Service
public class DemoService {
@Autowired
private DemoRepository repository;
@Transactional(timeout = 10)
public void sleep() {
repository.sleep();
}
}
package com.example.demo;
public interface DemoRepository {
void sleep();
}
package com.example.demo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Profile;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;
@Repository
@Profile("db2")
public class Db2DemoRepository implements DemoRepository {
@Autowired
private JdbcTemplate template;
@Override
public void sleep() {
template.execute("call SYSIBMADM.DBMS_ALERT.SLEEP(30)");
}
}
package com.example.demo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Profile;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;
@Repository
@Profile("postgres")
public class PostgresDemoRepository implements DemoRepository {
@Autowired
private JdbcTemplate template;
@Override
public void sleep() {
template.execute("select pg_sleep(30);");
}
}
Я полагаю, что тайм-аут транзакции устанавливает тайм-аут запроса в Postgres и не может это сделать в DB2. Также я безуспешно пытался использовать несколько значений для следующих свойств конфигурации DB2: timerLevelForQueryTimeOut, interruptProcessingMode, queryTimeout
.
Итак, на мои вопросы:
- Имеет ли способ, которым я пытаюсь воспроизвести проблему и протестировать несколько БД, имеет смысл или я что-то упустил?
- Это более важно ,: есть ли способ заставить соединение DB2 прервать именно в тот момент, когда истекает время транзакции достигает своего предела?