Hibernate LockAcquisitionException при очистке базы данных - PullRequest
0 голосов
/ 02 марта 2020

Я использую hibernate в моей среде тестирования автоматизации, некоторые сценарии ios требуют, чтобы я создавал тестовые данные (SQL записи), и я делаю это, используя hibernate. Я отслеживаю идентификаторы всех созданных записей, а затем я использую эти идентификаторы для создания и выполнения операторов DELETE SQL для очистки после моих тестов.

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

org.hibernate.exception.LockAcquisitionException

Причина: com.microsoft.sqlserver.jdb c .SQLServerException: транзакция (идентификатор процесса 149) заблокирована для ресурсов блокировки с другим процессом и была выбрана как жертва тупика. Повторите транзакцию.

Вот мой код «очистки базы данных»:

private void cleanDB()
{
    Session session = openSession();

    try
    {
        String combinedQuery = "";

        combinedQuery += Queries.createSetTablesConstraintEnabledQuery(true);
        Query query = session.createNativeQuery(combinedQuery);
        query.executeUpdate();
        closeSession(session);
    }
    catch (Exception e)
    {
        closeSession(session);
        Assert.fail("Failed cleaning Client DB! " + ExceptionUtils.getStackTrace(e));
    }
}

Где комбинированный запрос является SQL запрос, в котором я:

  1. установил НЕ проверять ограничения для каждой таблицы, из которой я буду удалять записи, например:

ALTER TABLE dbo.TableName NOCHECK CONSTRAINT ALL

удалить все записи из всех таблиц, используя идентификаторы, которые я отслеживал при создании записей, например:

DELETE FROM dbo.TableName WHERE (Id IN ("+ ids +" ))

Снова установите ограничения таблиц для всех таблиц, для которых я их отключил до

ALTER TABLE dbo.TableName CHECK CONSTRAINT ALL

Так как исключение посоветовал, я думал, что если я поймаю это исключение мертвой блокировки, я могу попытаться повторить процедуру очистки, поэтому я сделал следующее:

    private void cleanDB()
    {
        int count = 0;
        int maxTries = 5;
        int timeBetweenRetries = 3000;

        Session session = openSession();

        while (true)
        {
            try
            {
                String combinedQuery = "";

                combinedQuery += Queries.createSetTablesConstraintEnabledQuery(true);
                Query query = session.createNativeQuery(combinedQuery);
                query.executeUpdate();
                closeSession(session);
                return;
            }
            catch (Exception e)
            {
                closeSession(session);

                // wait before retry
                Thread.sleep(timeBetweenRetries);

                // handle exception
                if (++count == maxTries)
                {
                    Assert.fail("Failed cleaning Client DB! Tried [" + count + "] times, with [" + timeBetweenRetries + "] ms between retries! "  + ExceptionUtils.getStackTrace(e));
                    throw e;
                }
            }
        }
    }

Но, к сожалению, это не решает проблему, вместо мертвой блокировки исключение, теперь я иногда получаю:

org.hibernate.TransactionException: транзакция была помечена только для отката; не может выполнить фиксацию в org.hibernate.resource.transaction.backend.jdb c .internal.JdbcResourceLocalTransactionCoordinatorImpl $ TransactionDriverControlImpl.commit (JdbcResourceLocalTransactionCoordinatorImpl. java: 21It. . java: 68)

Есть идеи, как решить эту проблему?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...