`

改变 Grails 的缺省事务行为

阅读更多
Grails通过Service让我们不用进行任何配置就享受到了声明式事务这一特性。可是,这也让我们不得不接受它预先设置的事务行 为:PROPAGATION_REQUIRED。要是我想使用其它的事务行为该如何做呢?没关系,使用@Transactional进行配置就行了。

废话少说,直奔正题。下例就展示了自定义Grails事务行为的做法:

Domain1Service,其中的saveDomain1负责保存Domain1,该方法的行为是始终都启动一个新事务。在这个方法的末端抛出了一个RuntimeException,这将让Grails回滚事务。这是为了证明咱们的配置确实生效了。

package cases   
  
import org.springframework.transaction.annotation.*   
  
class Domain1Service {   
       
    def domain1Service   
  
    static transactional = true  
       
    @Transactional(propagation = Propagation.REQUIRES_NEW)   
    def saveDomain1() {   
        new Domain1().save()   
        throw new RuntimeException("save domain1 failed!")   
    }   
}  


Domain2Service,其中的saveTwoDomains负责保存Domain2,同时它还会调用Domain1Service的saveDomain1,它使用缺省的事务行为。

  package cases   
  
class Domain2Service {   
    def domain1Service   
  
    static transactional = true  
  
    def saveTwoDomains() {   
        new Domain2().save()   
        try{   
            domain1Service.saveDomain1()   
        }catch(e){   
            println 'save domain1 failed!'  
        }   
    }   
}  

这里没有给出Domain1和Domain2的代码,因为要创建它们并不难,而且在整个过程中它们的内容也不会有任何决定性的影响。

按照代码的意思,调用Domain2Service的saveTwoDomains,如果数据库里有Domain2而没有Domain1,那么我们 的配置就达到目的了。因为进入Domain1Service的saveDomain1之后,将产生一个新事务,而它在方法结束时会回滚,因此 Domain1不会保存。而saveTwoDomains,因为捕获并处理了saveDomain1的RuntimeException,因此不会在抛出 运行时异常,所以自己的事务可以正常结束,故Domain2得以保存。

要测试这个并不难,写一个集成测试就可以了。但是这次我太懒了,想直接用肉眼看看数据库的结果。记住,这不是推荐的做法,只适用于一次性的探索性测试。

首先,将DataSource配置成MySQL;接着,启动Grails Console。没错,我就是要在这个Console里直接获得咱们定义的Bean,然后手工触发方法的执行。

在Console里输入:ctx.getBean("domain2Service").saveTwoDomains()

正如期望的那样,Domain1失败的信息打印出来了。检查一下数据库吧,Domain2已经保存,而Domain1则完全不见踪影。配置生效了!

如果你还不放心,那么可以把saveDomain1中那句抛出RuntimeException的话注释掉,然后重新启动Console进行测试。这时,Domain1和Domain2都能正常保存。

一切都很美好,是不是。但请注意Spring文档里这样一段话:

引用

  在代理模式(这是缺省的)下,只有通过代理传入的外部方法调用才会被拦截。这意味着,自身的方法调用,在效果上是,目标对象内的方法A调用方法B,在运行时将不会产生实际的事务,即便被调用方法已经使用@Transactional进行了标记。


通过例子来说明这段话吧。对Domain1Service稍作修改:

  package cases   
  
import org.springframework.transaction.annotation.*   
  
class Domain1Service {   
  
    static transactional = true  
       
    @Transactional(propagation = Propagation.REQUIRES_NEW)   
    def saveDomain1() {   
        new Domain1().save()   
        throw new RuntimeException("save domain1 failed!")   
    }   
       
    def saveTwoDomains() {   
        new Domain2().save()   
        try{   
            saveDomain1()   
        }catch(e){   
            println 'save domain1 failed!'  
        }   
    }   
}  

这次在Console中运行

ctx.getBean("domain1Service").saveTwoDomains()

检查一下数据库,你会发现两个对象都保存了,这显然说明saveDomain1的事务配置并没有其作用。那么按照上面那句话和咱们刚才的实验,这是否就意味着,如果今后有类似情况,咱们就得写成2个类呢?不尽然。

根据Spring文档里的那段话,其关键在于只要让方法调用经过代理就行了。将上述代码saveTwoDomains中的代码 “saveDomain1()”换成“domain1Service.saveDomain1()”,然后重新运行测试,你会发现事务配置又生效了。

同时,这个实验也说明了,注入的对象并不是实际的Service对象。还是用代码来验证一下:


package cases   
  
import org.springframework.transaction.annotation.*   
  
class Domain1Service {   
       
    def domain1Service   
    ...       
    def test(){   
        println this.class  
        println domain1Service.class  
        this == domain1Service   
    }   
}  


运行测试,你会发现结果为false,而且打印类似下列语句:
class cases.Domain1Serviceclass cases.Domain1Service$$EnhancerByCGLIB$$69fcb82
分享到:
评论
1 楼 luckarecs 2012-05-19  
受益很多,谢谢!

相关推荐

    Grails Grails Grails

    Grails的控制器通过拦截器链进行扩展,可以添加自定义的行为和过滤逻辑。 **Grails 的核心特性** 1. **自动化配置和约定优于配置**:Grails 提供了许多默认配置,例如数据库连接、URL映射等,开发者只需按照约定...

    Grails权威指南 Grails权威指南

    《Grails权威指南》是一本全面深入探讨Grails框架的专著,旨在帮助读者掌握这一强大的Web开发工具。Grails是一种基于Groovy语言的开源框架,它为构建现代、高效的应用程序提供了简洁高效的解决方案。本指南针对不同...

    Eclipse下搭建Grails项目

    【Grails项目搭建详解】 Grails是一个基于Groovy语言的开源Web应用框架,它简化了开发过程,尤其适合快速构建动态网站。在Eclipse中搭建Grails项目可能相对复杂,但通过以下步骤,即使是初学者也能顺利进行。 1. *...

    grails中文入门简介

    在服务层,Grails支持声明式事务,并允许通过依赖注入将服务集成到应用程序中。服务的作用域和生命周期是Grails服务管理的一部分。Grails还支持使用Java服务,这允许Java开发者可以更容易地迁移到Grails。 测试是...

    grails-用户手册

    《Grails用户手册》 Grails,作为一个基于Groovy语言的开源Web应用框架,深受开发者喜爱,它简化了Java开发的复杂性,提供了强大的MVC(Model-View-Controller)架构,以及丰富的插件系统。这份用户手册将帮助你...

    grails 中文第二版

    - 支持自定义ORM映射,允许更细粒度地控制映射行为。 - 支持缺省排序,简化了查询结果的排序逻辑。 - 支持事务编程,提供了对事务边界和隔离级别的控制。 **GORM与约束** - GORM支持在领域类中定义约束,如唯一性...

    Grails入门指南 -- 针对grails1.0.4更新

    - 对于企业级应用有兴趣的开发者,尤其是需要利用Java生态系统的高级特性(如分布式事务、通信等)的场景。 #### 二、Grails环境搭建与基本应用 - **环境要求**: - **JDK5**及以上版本。 - **Grails1.0.4**版本...

    eclipse开发grails插件

    对于Grails开发,我们需要的是Eclipse中的Grails插件,它能够提供对Grails项目的创建、运行、调试等一系列功能。 **Grails**是基于Groovy语言的全栈式Web开发框架,它借鉴了Ruby on Rails的设计理念,提供了快速...

    eclipse插件grails(groovy)

    此外,Groovy的动态特性允许你在运行时添加或修改类的行为,这在快速迭代开发中非常有用。 Grails框架提供了丰富的插件系统,可以快速扩展功能。例如,如果你需要集成数据库,可以使用ORM框架GORM(Grails Object ...

    Grails1.1中文文档

    《Grails 1.1 中文文档》是一个非常宝贵的资源,尤其对于国内的开发者来说,由于Grails在中文社区中的资料相对较少,这份文档的价值不言而喻。Grails是一个基于Groovy语言的开源Web应用框架,它借鉴了Ruby on Rails...

    grails快速开发web

    ### Grails 快速开发 Web 应用程序 #### 一、Grails 概述 Grails 是一种基于 Groovy 的开源应用框架,用于简化 Web 应用程序的开发过程。它采用约定优于配置的原则,这使得开发者可以更快地创建功能丰富的 Web ...

    grails脚手架2次优化

    《Grails脚手架二次优化详解》 在Web开发领域,Grails...通过理解其工作原理,定制Controller和View,扩展Domain Class,注册自定义行为,以及性能优化,我们可以使Grails脚手架成为强大的开发工具,助力项目成功。

    grails-2.4.4.zip

    《Grails 2.4.4 框架深度解析》 Grails 2.4.4 是一个基于Java的开源Web应用框架,它利用Groovy语言的强大特性,为开发者提供了一种高效、灵活的开发环境。这个压缩包“grails-2.4.4.zip”包含了完整的Grails 2.4.4...

    Grails中文参考手册

    **Grails 概述** Grails 是一个基于 Groovy 语言的开源 web 应用程序框架,它构建在 Java 平台上,旨在提高开发效率,简化常见 Web 开发任务。Grails 遵循 Model-View-Controller (MVC) 架构模式,允许开发者快速...

    grails开发

    - **Services**:服务层封装业务逻辑,可被多个控制器复用,且支持事务管理。 4. **GORM(Grails Object Relational Mapping)** GORM是Grails的内置ORM框架,提供了数据访问接口,使得操作数据库如同操作对象...

    grails中文参考手册

    《Grails中文参考手册》是针对Groovy编程语言构建的Web应用框架——Grails的一份详尽学习资料。Grails以其高效、灵活和强大的特性,成为开发人员在Java平台上构建Web应用的热门选择。这份手册旨在帮助初学者快速上手...

Global site tag (gtag.js) - Google Analytics