2015-01-26 3 views
1

Я работал над приложением Grails и с помощью консольного плагина выполнял код во время выполнения. И при попытке сохранить объект получил исключение HibernateOptimisticLockingFailureException.Использование Grails withTransaction и пессимистического блокирования

Затем, после того, как поисковая система узнала, что использовать с Transaction, который работал нормально.

Show.withTransaction { 
    Show s=Show.get(1111) // any show id 
    s.name=s.name+'1' 
    s.save() 
} 

Я также попытался замок (пессимистический замок), который не работал и выброшенное исключение оптимистичной блокировки:

Show s=Show.lock(1111) 
s.name=s.name+'1' 
s.save(flush:true) 

почему пессимистическая блокировка фрагмент кода не работает?

Для получения более подробной информации:

class Content { 

    User createdBy 
    User lastUpdatedBy 
    Date dateCreated 
    Date lastUpdated 

    static constraints = { 
     createdBy nullable: true 
     lastUpdatedBy nullable: true 
    } 

    static mapping = { 
     tablePerHierarchy(false) 
    } 

} 

class Show extends Content { 

    String name 
    ShowCategory category 
    ShowType showType 

    static hasMany = [images: Image] 

    static constraints = { 
     name blank: false, unique: true 
     showType nullable: true 
     images nullable: true, blank: true 
     category nullable: true 
    } 

    static mapping = { 
     table("some_table_show") 
     images cascade: 'all-delete-orphan' 
     name index: 'name_idx' 
     images cache: true 
    } 

    def afterInsert() { 
     Plug.cacheService.deleteCache() // some redis cache usage 
    } 

    def afterUpdate() { 
     Plug.cacheService.deleteCache() // some redis cache usage 
    } 

} 

Exception after using lock (pessimistic locking): 
org.springframework.orm.hibernate3.HibernateOptimisticLockingFailureException: Object of class [com.myApplication.Show] with identifier [1111]: optimistic locking failed; nested exception is org.hibernate.StaleObjectStateException: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect): [com.myApplication.Show#1111] 
    at com.myApplication.cacheService.deleteCache(CacheService.groovy:286) 
    at com.myApplication.Show.afterUpdate(Show.groovy:161) 
    at org.grails.datastore.mapping.engine.event.AbstractPersistenceEventListener.onApplicationEvent(AbstractPersistenceEventListener.java:46) 
    at Script1.run(Script1.groovy:17) 
    at org.grails.plugins.console.ConsoleService.eval(ConsoleService.groovy:57) 
    at org.grails.plugins.console.ConsoleService.eval(ConsoleService.groovy:37) 
    at org.grails.plugins.console.ConsoleController$_closure2.doCall(ConsoleController.groovy:61) 
    at grails.plugin.cache.web.filter.PageFragmentCachingFilter.doFilter(PageFragmentCachingFilter.java:198) 
    at grails.plugin.cache.web.filter.AbstractFilter.doFilter(AbstractFilter.java:63) 
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145) 
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615) 
    at java.lang.Thread.run(Thread.java:745) 
Caused by: org.hibernate.StaleObjectStateException: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect): [com.myApplication.Show#1111] 
    ... 12 more 

ответ

-2

Пессимистический замок опирается на базу данных, чтобы реализовать поведение блокировки. Я заметил, что он работает с документацией MySQL и Microsoft SQL Server, но не с базой данных H2, используемой в среде разработки Grails.

+0

Да, обычно функциональность базы данных зависит от базы данных для ее реализации. Вы, должно быть, делали это неправильно - H2 поддерживает блокировку и даже поддерживает MVCC. Включите ведение журнала SQL и выполните что-то вроде 'Show.lock (1111) ', и вы увидите SQL, похожий на' select ... from ... where ... for update', причем 'for update' является ключевой частью. Обратите внимание, что блокировка имеет смысл только в транзакции, поскольку это временной интервал, в течение которого блокировка должна быть активной, а диспетчер транзакций освобождает блокировку при совершении или откате. –

+0

Да, я видел эту блокировку mysql для обновления в журналах запросов в спящем режиме. Но не знаю, почему это оптимистичное исключение блокировки. – Lovin

2

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

Было бы сложно предоставить помощь без дополнительной информации о том, как выглядел ваш код, и сообщения об ошибке, которое вы видели. Если вы можете воспроизвести, что это поможет много.

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

Это умеренно вероятно, что оптимизация блокировки спящего режима/исключение при спящем режиме при использовании пессимистической блокировки. Если вы посмотрите на Hibernate SQL для обновлений, это обычно что-то вроде update <tablename> set foo=?, bar=?, ... where id=? and version=?. Предложение where переопределено - достаточно просто указать идентификатор, так как это либо идентификатор, который соответствует существующей строке, либо нет. Но он проверяет счет обновления JDBC после запуска этого SQL, и если он равен нулю, значение version должно быть отключено, и предполагается, что это должно было быть вызвано кем-то другим, редактирующим файл и увеличивающим версию.

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

+0

Большое спасибо за такой быстрый ответ, как просили добавить дополнительные детали. – Lovin

+0

похоже, что исключение генерируется из кода удаления кеша, который является вызовом redis. Внутри этого вызова происходит простое удаление redis. Не могу понять, почему это исключение происходит. – Lovin

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