2014-11-14 2 views
1

Прежде всего, я использую модифицированную версию Spring Security для проверки подлинности Active Directory, а также проверку наличия разрешений доступа, хранящихся в базе данных. Это означает, что вызов в нормальном Groovy класса для загрузки информации из базы данных:Grails - Зачем нужен Transaction?

if (Holders.config.loadRolesFromDatabase) 
{ 
    Set<DomainClassRole> roles = DomainClassUser.findByUsername(username)?.roles 
    if (roles) 
    authorities.addAll(roles.collect({ new SimpleGrantedAuthority('ROLE_' + it.name) })) 
} 

Это работает большое с Hibernate 4.3.6.1 и Tomcat 7.0.54, однако, после модернизации и (до 4.3. 10.18 и 8.0.14.1) теперь он вызывает исключение «HibernateException: No Session found for current thread» при вызове метода динамического поиска. После выполнения некоторых исследований я решил обернуть этот код в withTransaction блоке:

if (Holders.config.loadRolesFromDatabase) 
{ 
    DomainClassUser.withTransaction({ 
    Set<DomainClassRole> roles = DomainClassUser.findByUsername(username)?.roles 
    if (roles) 
     authorities.addAll(roles.collect({ new SimpleGrantedAuthority('ROLE_' + it.name) })) 
    }) 
} 

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

+0

Не знаете, почему поведение изменилось, и у вас нет сеанса, но, возможно, вы можете использовать 'withNewSession' вместо' withTransaction' для (возможно) лучшей производительности и более описательного кода? –

ответ

1

This is why you need Transactions даже если считывание данные. Все операторы базы данных должны регистрироваться в физической транзакции, поэтому вы не используете их. Когда вы явно не используете границу транзакции, вы просто переходите в режим автоматической фиксации, поэтому каждый оператор выполняется в отдельной транзакции базы данных (что является большим объемом служебных данных). Не говоря уже о чрезмерной нагрузке на решение для объединения соединений.

3

Существует статический метод withSession, который выглядит так, как будто это будет то, что вам нужно здесь, но это не так; к сожалению, он делает доступным текущий сеанс Hibernate, но если нет активного/текущего сеанса, он не создает его. Но withTransaction делает, потому что при использовании Hibernate в Grails Spring PlatformTransactionManager - это HibernateTransactionManager, который обеспечивает активный сеанс на протяжении всей транзакции и сбрасывает и закрывает его перед фиксацией (если не было явного или автоматического (исключение - вызванный) откатом).

Так что это немного взломать, чтобы использовать withTransaction таким образом, поскольку вы полагаетесь на побочный эффект, но вы все равно идете в базу данных, поэтому накладные расходы транзакции (на самом деле только начальные вызовы на соединение для установки autocommit на false, уровень изоляции и т. д. и вызов фиксации no-op в конце) является незначительным и вообще не вызывает беспокойства. Нам действительно нужно что-то между withSession и withTransaction, что делает сеанс доступным и создает его на время текущего кода, но без ненужной транзакции.

+1

Так это значит, где с NewSession вписывается - в grails 2.4.5? Я спрашиваю, как я использую withNewSession, но затем я получаю ту же ошибку, что и выше: «Нет сеанса, найденного для текущего потока» и, следовательно, попал на этот пост SO. Итак, мне кажется, что мне все-таки нужно было сделать это с помощьюNewSession {withTransaction {...}}. –

1

Вы должны использовать withNewSession(). Согласно документации, он доступен с доисторических Grails 1.2.0.

Краткое резюме:

  • withSession() - делает текущий сеанс Hibernate доступен (если он существует, в противном случае вы получаете "Нет Session найден для текущего потока")
  • withNewSession() - создает новый сеанс Hibernate без запуска транзакции (Я считаю, что самое лучшее решение для вас)
  • withTransation() - начинает и совершает сделку (не лучший выбор для простого считывания только операции)

(проверено на Grails 3.1.13)