Extbase: реализовать блокировку для одновременного доступа

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

Для обработки этих операций я реализовал задачу планировщика (расширение «планировщик» 6.2.0). Теперь дело в том, что шаги каждой операции должны выполняться один за другим, а не параллельно. Это означает: при запуске задача планировщика должна найти очередную «свободную» операцию, заблокировать ее и обработать.

Для блокировки в таблице базы данных с операциями есть целочисленный столбец "isLocked". Поэтому я хотел использовать следующий оператор SQL для блокировки операции:

$lockID = time(); 'UPDATE operations SET isLocked = '.$lockID.' WHERE isLocked = 0 AND uid = '.$freeOperationFound->getUid().';'

После этой команды SQL я хотел проверить, установлена ​​​​ли блокировка:

$repository->findOneByIsLocked($lockID);

Если блокировка прошла успешно, можно начать обработку шага операции.

Если в это время другой экземпляр задачи планировщика блокирует эту операцию, приведенный выше оператор SQL ничего не делает из-за условия: WHERE isLocked = 0.

Проблема в том, что Extbase игнорирует операторы SQL UPDATE.

Если я просто обновлю объект свободной операции через репозиторий, блокировка другого экземпляра задачи может быть перезаписана. Мне нужно какое-то "условное" обновление.


person firelex    schedule 30.04.2016    source источник
comment
Как вы называете свой оператор SQL? Почему бы не использовать extbase для обновления объектов? Если у вас нет веских причин не использовать extbase и вам нужна помощь, я напишу подробный ответ.   -  person sven    schedule 02.05.2016
comment
Дело в том, что я не могу вызвать этот SQL-утверждение, потому что Extbase его игнорирует. Если я обновлю объект - я рискую перезаписать блокировку другого экземпляра, которая устанавливает его блокировку между моими операциями чтения и записи. И да! - Я был бы очень признателен, если бы вы могли написать некоторые подробности.   -  person firelex    schedule 03.05.2016


Ответы (2)


Кажется, я понял: $GLOBALS['TYPO3_DB']->exec_UPDATEquery — это ответ.

Остается только один вопрос: не устарел ли этот метод в FLOW, как $query->statement в репозитории.

person firelex    schedule 05.05.2016

Хотя функция exec_UPDATEquery из класса DatabaseConnection, безусловно, выполняет свою работу, вот решение через extbase. Это может иметь больше смысла, если вам нужно работать с объектом операции после его блокировки.

$persistenceManager = GeneralUtilities::makeInstance('TYPO3\CMS\extbase\Persistence\PersistenceManager');

$freeOperation = $repository->findOneByIsLocked(0);
$freeOperation->setIsLocked(time());

$repository->update($freeOperation);
$persistenceManager->persistAll();

$freeOperation->myOperation();
$freeOperation->myOtherOperation();

$freeOperation->setIsLocked(0);
$repository->update($freeOperation);
$persistenceManager->persistAll();

Причина, по которой вам нужно сохраняться вручную, заключается в том, что ваша задача не находится в контексте действия ActionController. И даже если бы вы были, он не сохранял бы ваши изменения автоматически до конца действия. Выполнение этого через extbase может быть более безопасным вариантом, потому что вы можете быть уверены, что действительно работаете с той же операцией, которую вы только что заблокировали.

person sven    schedule 12.05.2016
comment
Я думаю, что это не сработает: что, если тем временем другой экземпляр попытается заблокировать ту же запись: посмотрите на этот сценарий: **A**...$repository->findOneByIsLocked(0); **B**...$repository->findOneByIsLocked(0); **A**...->setIsLocked(time()); **A** $repository->update($freeOperation); **A**$persistenceManager->persistAll(); **B (по какой-то причине позже как A)**...->setIsLocked(time()); **B**$repository->update($freeOperation); **B**$persistenceManager->persistAll(); Мы получаем следующее: A думает, что он заблокировал запись, а B думает, что заблокировал! - person firelex; 12.05.2016