Grails/ Hibernate: добавить пессимистическую блокировку при использовании Creteria

Я попытался добавить пессимистическую блокировку в свой creteria, как показано в документе http://grails.org/doc/latest/guide/GORM.html но у меня было исключение:

"ОШИБКА util.JDBCExceptionReporter - функция не поддерживается: "FOR UPDATE && JOIN"; оператор SQL: ... org.hibernate.exception.GenericJDBCException: не удалось выполнить запрос"

Я пытался добавить блокировку в двух местах:

def ParentInstance = Parent.createCriteria().get {
    Childs {
            idEq(ChildInstance.id)
            lock true
    }

А также

def ParentInstance = Parent.createCriteria().get {
    Childs {
            idEq(ChildInstance.id)      
    }
    lock true               
}

Дополнительный вопрос: правильно ли использовать пессимистическую блокировку ассоциации?

Спасибо

Домен

class Parent{   
     static hasMany = [Childs:Child]    
}

class Child{

}

DataSource.groovy

        dataSource {
            pooled = true
            driverClassName = "org.h2.Driver"
            username = "sa"
            password = ""
        }
        hibernate {
            cache.use_second_level_cache = true
            cache.use_query_cache = false
            cache.region.factory_class = 'net.sf.ehcache.hibernate.EhCacheRegionFactory'
        }
        // environment specific settings
        environments {
            development {
                dataSource {
                    dbCreate = "update" // one of 'create', 'create-drop', 'update', 'validate', ''
                    url = "jdbc:h2:myApp_prodDb;MVCC=TRUE"
                }
            }
            test {
                dataSource {
                    dbCreate = "update"
                    url = "jdbc:h2:mem:myApp_testDb;MVCC=TRUE"
                }
            }
            production {
                dataSource {
                    dbCreate = "update"
                    url = "jdbc:h2:myApp_prodDb;MVCC=TRUE"
                    pooled = true
                    properties {
                       maxActive = -1
                       minEvictableIdleTimeMillis=1800000
                       timeBetweenEvictionRunsMillis=1800000
                       numTestsPerEvictionRun=3
                       testOnBorrow=true
                       testWhileIdle=true
                       testOnReturn=true
                       validationQuery="SELECT 1"
                    }
                }
            }
        }

1 ответ

Решение

В зависимости от того, как вы формируете запрос, Hibernate будет выполнять разные запросы. То, как написан ваш запрос, Hibernate выполнит соединение - это может быть полезно для производительности, потому что это означает, что ваши объединенные сущности уже будут предварительно извлечены в 1 запросе. Однако для блокировки это плохо, так как каждая объединенная таблица должна быть заблокирована, и это может оказать значительное влияние на глубокие иерархии. Таким образом, ваша база данных не позволяет этого (я даже не уверен, что любой другой делает).

Вы должны будете выполнить свой запрос без объединений. В зависимости от вашей реализации класса домена простой Child.parent.id можно сделать, не касаясь базы данных, и тогда ваш запрос становится простым Parent.lock(Child.parent.id), Трудно сказать, не видя реальных классов домена.

Что вы всегда можете сделать, это получить Parent в неблокирующем запросе, а затем вызвать lock() метод на возвращенном экземпляре. Я бы посоветовал вам взглянуть на эту прекрасную статью о блокировке вещей в GORM для получения дополнительной информации.

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