Grails 2.5: сложный "findOrCreate" и синхронизация между потоками (сеансы HTTP)

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

level1/level2/document

объект level2 Рекомендации level1 а также document Рекомендации level2,

Несколько объектов, использующих один и тот же подпуть level1/level2, могут загружаться параллельно, и поэтому необходимо реализовать синхронизацию между сеансами. Каждая из учетных записей может иметь свою собственную структуру.

По сути, логика похожа на расширенный findOrCreate, который должен быть синхронизирован между несколькими одновременными запросами.

Моя идея заключалась в том, чтобы реализовать что-то вроде этого внутри метода службы:

Doc d
synchronised(currentUser) {
    Dir.withNewTransaction {
       Dir l1 = findFirstLevel(level1) // (A)
       if (!l1) {
           l1 = new Dir(name: level1)
           l1.save()
       }
       Dir l2 = findSecondLevel(l1, level2)
       if (!l2) {
           l2 = new Dir(name: level2, parent: l1)
           l2.save()
       }
       d = new Doc(name: docName, parent: l2)
       d.save()
    } // (B)
} // (C)
saveDocumentContent(d, content)

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

Однако данные не сохраняются до тех пор, пока сервисная функция, запущенная в потоке T1, не завершится. Это приводит к тому, что запрос, помеченный (A), возвращает нуль в потоке T2, который был заблокирован блоком синхронизации и введен до того, как T1 завершит выполнение метода обслуживания. Это приводит к такой структуре:

D1/D2/D3
D1/D2/D4

Вместо

D1/D2/D3
     /D4

Мое предположение было, что в (B) в конце withNewTransaction данные будут сохранены, и затем параллельная сессия, запущенная в T2, получит данные, используя запрос.

Однако этого не происходит.

Что я упустил?

РЕДАКТИРОВАТЬ: Очистка сеанса в начале и очистки в конце синхронизированного раздела не имеет никакого эффекта.

РЕДАКТИРОВАТЬ 2: Hibernate 3.6 используется с Grails. Может ли это быть источником проблемы?

1 ответ

Решение

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

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