2015-11-27 2 views
0

фонИспользование SERIALIZABLE изоляции транзакций с Alfresco

Alfresco использует изоляцию транзакции базы данных по умолчанию, который для нашей базы данных Oracle является READ_COMMITED. Я работаю над проектом, где неповторяющиеся и фантомные чтения могут быть серьезной проблемой, поэтому я изучаю использование изолированной транзакции SERIALIZABLE, чтобы избежать этого.

С одной стороны, у нас будет пользовательская служба API, которая группирует изменения в атомные транзакции - в основном операции CRUD в документах. С другой стороны, мы будем иметь фоновые процессы, обновляющие метаданные этих документов, которые выполняются параллельно.

Эти операции будут использовать запросы транзакционных метаданных, чтобы не усложнять ситуацию, добавляя в состав последовательно согласованные запросы SOLR.

Целью является возможность переноса основной модели метаданных во время работы службы API. Для целей этого вопроса я собираюсь использовать один атрибут в качестве примера, но в IRL будет много изменений такого рода. Например, в настоящее время у нас есть поле метаданных с ограничением: mymodel: doctypes1. Но нам нужно переназначить значения в mymodel: doctypes1 в новое поле с другим ограничением: mymodel: doctypes2. (Не спрашивайте меня, почему, я не могу контролировать это решение, и я лично сомневаюсь в мудрости такого рода изменений).

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

  • Фоновый процесс начинает транзакцию и считывает значение MyModel: doctypes1.
  • API пишет изменение mymodel: doctypes1 перед тем, как выполняется фоновый процесс.
  • Фоновый процесс обновляет значение mymodel: doctypes2 на основе исходного значения mymodel: doctypes1.

Эти два значения теперь несовместимы: я считаю, что эта ошибка называется неповторяющимся чтением.

Вопросы

ли установка базы данных Oracle для SERIALIZABLE предотвратить эту проблему? Alfresco использует весенние транзакции под капотом. Я понимаю, что сериализованная tx-изоляция с транзакциями Spring предотвратит «прозрачность» этой проблемы.

Есть ли у кого-нибудь реальный опыт в мире настройки базы данных Alfresco для SERIALIZABLE? Вы пытались решить подобную проблему? Это сработало? Какое влияние на производительность оказало это для вас?

Спасибо, что поделились своими впечатлениями!

+0

Если вы используете Oracle с Alfresco, вы используете платный Alfresco One Enterprise. Это означает, что вы получаете поддержку - просто дайте им кольцо/поднимите билет, и они свяжут вас с одной из горстки инженеров Alfresco, которые действительно действительно знают этот материал! – Gagravarr

ответ

2

Axel Faust на форуме Alfresco помог мне в этом, указав, что RetryingTransactionHelper обеспечивает оптимистичную блокировку и повторяет попытку, если две транзакции перекрываются. Если вам интересно, я бы рекомендовал его сообщение.

https://forums.alfresco.com/forum/developer-discussions/repository-services/using-serializable-transaction-isolation-alfresco

Просто, чтобы убедиться, что я сделал немного макет, чтобы спровоцировать ConcurrencyException и проверить, что он действительно ведет себя правильно.

Я использую мастер-класс для отправки 49 обновлений для того же узла в пул потоков:

for (int i=0; i < 50; i++) { 
     TestIncrementer ti = new TestIncrementer(node); 
     threadPoolExecuter.submit(ti); 
    } 

Мой инкрементора просто читает существующее название, спит в случайном порядке, а затем добавляет на него.

int hash = RetryingTransactionHelper.getActiveUserTransaction().hashCode(); 
    log.debug("Thread id: " + Thread.currentThread().getId() + " tx " + hash); 
    String title = (String) nodeService.getProperty(nodeRef, ContentModel.PROP_TITLE); 
    Thread.sleep(Math.round(Math.random()* 1000)); 
    nodeService.setProperty(nodeRef, ContentModel.PROP_TITLE, title + "1"); 
    log.debug("Title: " + title); 

Как и следовало ожидать, я вижу исключение параллелизма и повторные попытки:

Transaction commit failed: 
    Thread: defaultAsyncAction4 
    Txn: UserTransaction[[email protected]65b249f2, status=0] 
    Iteration: 8 
    Exception follows: 
org.springframework.dao.ConcurrencyFailureException: Failed to update node 126094 

Но они получают повторены.

Последняя попытка удаляет узел с ровно 49 агрегатами! Именно это и должно произойти.

Вывод состоит в том, что изменение изоляции базы данных, безусловно, не является необходимым или даже нежелательным, если вы используете RetryingTransactionHelper для фоновых процессов.

Смежные вопросы