2012-01-23 37 views
6

在Grails应用程序中,服务方法的默认行为是它们是事务性的,并且如果抛出未经检查的异常,事务将自动回滚。但是,在Groovy中,不会强制处理(或重新抛出)检查的异常,因此如果服务方法抛出检查的异常,则事务将不会回滚。考虑到这一点,似乎是可取的每个标注的Grails服务类Grails服务交易行为

@Transactional(rollbackFor = Throwable.class) 
class MyService { 

    void writeSomething() { 
    } 
} 

假设我有MyService其他方法,其中一个只读取数据库,以及其他不接触DB,有以下几种注释是否正确?

@Transactional(readOnly = true) 
void readSomething() {} 

// Maybe this should be propagation = Propagation.NOT_SUPPORTED instead? 
@Transactional(propagation = Propagation.SUPPORTS) 
void dontReadOrWrite() {} 

为了回答这个问题,我想你需要知道我的意图是:

  • 如果异常是从任何方法抛出并有正在进行的交易,它会被回滚。例如,如果writeSomething()调用dontReadOrWrite(),并且从后者抛出异常,则由前者开始的事务将被回滚。我假设rollbackFor类级别的属性被各个方法继承,除非它们明确地覆盖它。
  • 如果有正在进行的任何事务,一个将不会启动对像dontReadOrWrite
  • 方法如果没有交易正在进行时readSomething()时,一个只读事务将会启动。如果正在进行读写事务,它将参与此事务。

回答

1

我认为你正在寻找的是更细化的事务管理,并且使用@Transactional注释是正确的方向。也就是说,有一个Grails Transaction Handling Plugin可以给你你正在寻找的行为。需要注意的是,您将需要在DomainClass.withTransaction闭包中包装服务方法调用,并将您寻找的非标准行为作为参数映射提供给withTransaction()方法。

作为一个说明,在后端,这是通过使用@Transactional注释来改变事务在运行时的行为,正是你正在谈论的。插件文档非常好,所以我不认为你会发现自己没有足够的指导。

希望这是你在找什么。

4

您的代码是正确的:您确实希望在您的服务类中的单个方法上使用Spring @Transactional注释来获得您要查找的粒度,您是对的,您希望SUPPORTS for dontReadOrWrite(NOT_SUPPORTED将暂停现有的事务,根据您所描述的内容,这些事务不会为您购买任何东西,并且需要您的软件花费周期,所以没有增益会有痛苦),并且您想要默认传播行为(REQUIRED)用于readSomething。

但是,要记住Spring事务性行为,一个重要的事情是Spring通过将您的类包装在执行相应事务设置的代理中,调用您的方法并在相应事务拆除时执行事务管理控制返回。并且(关键地),这个事务管理代码是只有在代理上调用方法时调用,如果writeSomething()直接调用第一个项目符号中的dontReadOrWrite(),则该方法不会发生。

如果你需要一个多数民众赞成通过另一种方法,你有两个选择,我知道,如果你想使用Spring的@Transactional注解的事务管理,不断的调用方法不同的事务行为:

  1. 移动该方法被另一个调用到不同的服务类中,该服务类将通过Spring代理从您的原始服务类访问。
  2. 将方法留在原来的位置。在您的服务类中声明一个成员变量,使其与您的服务类的接口具有相同的类型,并使其成为@Autowired,它将为您提供对服务类的Spring代理对象的引用。然后,当你想用不同的事务行为调用你的方法时,在该成员变量上而不是直接执行它,并且Spring事务代码将按照你想要的方式触发。

方法#1是巨大的,如果这两种方法真的不反正关系,因为它解决了你的问题,而混淆谁最终维护你的代码,而且也没有办法不小心忘记调用支持事务的方法。

方法#2通常是更好的选择,假设你的方法都在同一个服务中有一个原因,你不会真的想把它们分开。但是如果维护人员不理解Spring交易的这种皱纹,那么你必须记得在每个你称之为的地方调用它,所以这是有代价的。我通常愿意付出这样的代价,不会让我的服务班不自然地分化,但一如既往,这取决于你的情况。