Обработка исчерпания пула соединений и предотвращение взаимоблокировки в Hibernate/C3P0

Мои старые приложения следуют цепочке для запроса моей базы данных: Spring Tx -> Hibernate -> C3P0, Теперь мне нужно реализовать новые функции на основе существующей архитектуры.

Я обычно вхожу в транзакционный контекст, используя либо @Transactional аннотации или вручную вызывая PlatformTransactionManager,

Иногда для выполнения асинхронных операций и операций с большими данными я открываю сеанс без сохранения состояния, используя SessionFactory API. У нас никогда не было никаких дополнительных проблем, так как наш пул потоков хорошо контролируется

Впервые мое требование состоит в том, чтобы выполнять несколько операций с БД параллельно, чтобы повысить производительность. У меня есть сомнения по этому поводу, потому что я очень осторожен с многопоточными операциями.

Для каждого объекта в базе данных я могу выполнить операцию согласования в отдельном потоке. Но каждая операция согласования использует пару соединений для каждого из двух потоков, которые она порождает. Таким образом, в основном есть 4 соединения для каждого потока.

Класс многопоточности учит студентов, что во избежание тупиковой ситуации (проблема с едой философов) ресурсы должны быть получены транзакционным способом: как только вы приобрели вилку, если вы не можете приобрести вторую за разумное время, отпустите первую и попробуйте снова,

Мой вопрос прост. Учитывая SessionFactory API, как я могу написать код, который не будет бесконечно ждать 4 соединений от c3p0, если пул полон? Я имею в виду мне нужно 4 StatelessSessions только если есть место для 4, иначе я могу подождать и повторить попытку.

Насколько я знаю, SessionFactory API блокирует и не позволяет установить сторожевой таймер

1 ответ

Решение

В настоящее время идея заключается в использовании простого старого обходного пути.

В целом, в мире Java, если API не предлагает сторожевой метод для получения ресурса, вы можете делегировать его Future, который предлагает get(int timeout, TimeUnit timeUnit) API для ограничения выполнения.

Шаг 1: сторожевой таймер для получения ресурса

Итак, в основном, как я могу получить сеанс без сохранения состояния в рамках тайм-аута?

private Future<StatelessSession> getStatelessSession(SessionFactory sessionFactory)
{
    return asyncTaskExecutor.submit(new Callable<StatelessSession>()
    {

        @Override
        public StatelessSession call() throws Exception
        {
            return sessionFactory.openStatelessSession();
        }
    });
}

try {
    StatelessSession session = getStatelessSession(sessionFactory).get(3000,TimeUnit.MILLISECONDS);
} catch (TimeoutException e) {
    // go to step 2
}

Шаг 2: ешь так, как поступил бы философ

Как я уже сказал, моя проблема в основном похожа на ресторанного философа, за исключением того, что у нас есть не просто две вилки, а ложки и ножи, которые можно взять в общей сложности 4 штуки.

StatelessSession session1, session2, session3, session4;
for (int i=0; i<MAX_ATTEMPTS;i++) {
    try {
        session1 = tryGetSessionOrBoooooom();
    } catch(TimeoutException ex) {
        continue;
    }
    try {
        session2 = tryGetSessionOrBoooooom();
    } catch(TimeoutException ex) {
        session1.close();
        continue;
    }
    try {
        session3 = tryGetSessionOrBoooooom();
    } catch(TimeoutException ex) {
        session2.close();
        session1.close();
        continue;
    }
    try {
        session4 = tryGetSessionOrBoooooom();
    } catch(TimeoutException ex) {
        session3.close();
        session2.close();
        session1.close();
        continue;
    }
}

Что произойдет, если вы выйдете за пределы MAX_ATTEMPTS зависит от вас, разработчик!

Другие вопросы по тегам