Я использую 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 запрос, в котором я:
- установил НЕ проверять ограничения для каждой таблицы, из которой я буду удалять записи, например:
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)
Есть идеи, как решить эту проблему?