首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Grails 2.5.6事务回滚

Grails 2.5.6事务回滚
EN

Stack Overflow用户
提问于 2017-11-02 10:13:14
回答 2查看 646关注 0票数 2

如果发生错误或域类无效,我要做的主要工作是返回到编辑页面。我有一个User对象,它包含一个Person对象作为属性。

我的控制器看起来是这样的:

代码语言:javascript
复制
Object update(){
     User.withTransaction{status ->
        try {
            personDaoService?.bindObject(person, params)
            person.validate()
        } catch(Exception e){
            log.error(e.printStackTrace()) 
            status.setRollbackOnly()
        }

        if(person.hasErrors()){ 
            status.setRollbackOnly()
        }
        if(status.isRollbackOnly()){
            person.discard()
            person.refresh()
            return render(view: 'edit', model:[user:user, person:person], params: params)
        }

       try {
            userDaoService?.bindObject(person, params)
            user.validate() 
        } catch(Exception e){
            log.error(e.printStackTrace()) 
            status.setRollbackOnly()
        } 

        if(status.isRollbackOnly()){
            user.discard()
            user.refresh()
            return render(view: 'edit, model:[user:user, person:person], params: params)
        }       
    }
}

当返回到编辑页面时,我总是得到一个异常,它告诉我没有打开会话来加载person对象。

为了快速解决这个问题,我在用户对象的映射中添加了lazy:false,但结果不幸的是整个项目运行非常缓慢,所以我不得不删除lazy:false映射选项。

现在我想找个办法让它再起作用。

为什么hibernate在回滚时关闭会话?

我怎样才能重开会议?

编辑:

在设置回滚之前,我尝试呈现视图:

代码语言:javascript
复制
if(person.hasErrors()){                        
    person.errors.allErrors.each{user.errors.rejectValue("person", "", "${validationTagLib.message(error: it)}")}
    render(view: 'edit', model: [user: user], params: params)
    status.setRollbackOnly()
    return
}

这导致了这个异常:org.hibernate.LazyInitializationException: could not initialize proxy - no Session

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2017-11-06 10:55:12

我在DomainClasses中创建了一个方法来加载所需的所有对象,并在返回到编辑页面时调用该方法:

代码语言:javascript
复制
 Object update(){
     User.withTransaction{status ->
        try {
            personDaoService?.bindObject(person, params)
            person.validate()
        } catch(Exception e){
            log.error(e.printStackTrace()) 
            status.setRollbackOnly()
        }

        if(person.hasErrors()){ 
            status.setRollbackOnly()
        }
        if(status.isRollbackOnly()){
            person.discard()
            person.refresh()
            loadObject(person)
            return render(view: 'edit', model:[user:user, person:person], params: params)
        }

       try {
            userDaoService?.bindObject(person, params)
            user.validate() 
        } catch(Exception e){
            log.error(e.printStackTrace()) 
            status.setRollbackOnly()
        } 

        if(status.isRollbackOnly()){
            user.discard()
            user.refresh()
            loadObject(user)
            return render(view: 'edit', model:[user:user, person:person], params: params)
        }       
    }
}

加载类型为domainClass的所有属性的方法如下所示:

代码语言:javascript
复制
void loadObject(Object object, List<Object> loadedObjects = []){
    loadedObjects.add(object)
    for(MapEntry propertyEntryMap in object.properties){
        Object property = propertyEntryMap?.value
        if(grailsApplication.isDomainClass(property.getClass())){
            if(!loadedObjects.contains(property))
                loadObject(property, loadedObject)
        }
    }
    if(object.hasProperty("hasMany")){  
        for(def manyProperty in object.hasMany){
            for(Object property in object."${manyProperty.key}"){
                if(grailsApplication.isDomainClass(property.getClass())){
                   if(!loadedObjects.contains(property))
                       loadObject(property, loadedObject)
                }
            }
        } 
    }
}

唯一可以解决的问题是,hasMany关系可能太大了,这会减慢它的速度。

为了解决这个问题,我向DomainClass添加了一个属性,该属性包含应该加载的hasMany关系:

代码语言:javascript
复制
static lazyProperties = ['addresses']

此属性影响将跨越该列表中属性的loadObject方法:

代码语言:javascript
复制
void loadObject(Object object, List<Object> loadedObjects = []){
    loadedObjects.add(object)
    for(MapEntry propertyEntryMap in object.properties){
        Object property = propertyEntryMap?.value
        if(object.hasProperty('lazyProperties')){ // check if object contains the property 'lazyProperties'
            if(object?.lazyProperties?.contains(propertyEntryMap.key))
                continue
        }
        if(grailsApplication.isDomainClass(property.getClass())){
            if(!loadedObjects.contains(property))
                loadObject(property, loadedObject)
        }
    }
    if(object.hasProperty("hasMany")){  
        for(def manyProperty in object.hasMany){
            if(object.hasProperty('lazyProperties')){ // check if object contains the property 'lazyProperties'
                 if(object?.lazyProperties?.contains(manyProperty.key))
                     continue
            }
            for(Object property in object."${manyProperty.key}"){
                if(grailsApplication.isDomainClass(property.getClass())){
                   if(!loadedObjects.contains(property))
                       loadObject(property, loadedObject)
                }
            }
        } 
    }
}
票数 2
EN

Stack Overflow用户

发布于 2017-11-02 23:32:06

试图对上面的评论进行扩展。

这个错误意味着发生了严重的错误,因此hibernate必须关闭会话。

考虑到这个控制器:

代码语言:javascript
复制
 def doSomething() {

        SomeBean bean = new SomeBean(params.long('id'))
        bean.updateUser=userService.currentUser
        try {
            serice.foSomething(bean)
        } catch (ValidationException ve) {
            flash.message=message(error:ve.errors.getGlobalError())?:ve.errors
        } catch (DataIntegrityViolationException e) {
        } catch (HibernateObjectRetrievalFailureException e) {

        } catch (Throwable t) {
            flash.message= t.toString()
        }
        redirect(controller:'someController', action:'list')
    }

它有这么多尝试捕获的原因是因为我发现,例如,对于我正在获取HibernateObjectRetrievalFailureException的一段代码,但是实际的工作已经完成了--这使得您所勾勒出的这种secnario发生了--或者可能发生。

我的意思是,尝试在服务方法周围使用try捕获,并计算出首先发生了什么。

最重要的是,前3次尝试捕捉实际上告诉控制器继续进行--忽略这些问题(我认为在本例中它们都是这样),但是如果没有重定向,您可以在可抛出的段中添加一些子句或重定向,所以您可以选择其他地方,或者忽略它。

要完成以上所有内容,这可能对你有帮助将修复您的问题。

代码语言:javascript
复制
import grails.validation.ValidationException
class AuthorService {

    void updateAge(id, int age) {
        def author = Author.get(id)
        author.age = age
        if (!author.validate()) {
            throw new ValidationException("Author is not valid", author.errors)
        }
    }
}

基本上,当您最终捕获问题并找出导致问题的原因时,您可以在它发生之前捕获它,并返回您自己的自定义验证异常。

这将被你的标准故障所发现,其他的一切都会顺利地完成。

您的图层可以验证并确保一切正常--您显示的当前验证层--而问题其实并不在这里--当您要求Hibernate并去做一些无效的事情时--删除不能移除的东西--做一些它不能删除的事情--然后破坏它,并引起您当前的头痛--因此,在发生之前捕获它们,然后做上面的操作将是如何解决这些问题的。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/47072654

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档