spring – Grails服务交易行为

在Grails应用程序中,服务方法的默认行为是它们是事务性的,如果抛出未经检查的异常,事务将自动回滚.但是,在Groovy中,不会强制处理(或重新抛出)已检查的异常,因此存在一种风险,即如果服务方法抛出已检查的异常,则不会回滚该事务.考虑到这一点,似乎建议注释每个Grails服务类

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

    void writeSomething() {
    }
}

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

@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()时没有进行任何事务,则将启动只读事务.如果正在进行读写事务,它将参与此事务.

最佳答案
您的代码是正确的:您确实希望在服务类中的各个方法上使用Spring @Transactional注释来获得您正在寻找的粒度,您是否正确需要SUPPORTS for dontReadOrWrite(NOT_SUPPORTED将暂停一个现有的交易,根据你所描述的内容不会给你买任何东西,并且需要你的软件花费周期,所以没有收获就很痛苦,而且你想要默认的传播行为是正确的(必须的) )for readSomething.

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

如果你需要在另一个方法调用的方法上有不同的事务行为,那么如果你想继续使用Spring的@Transactional注释进行事务管理,你有两个我知道的选择:

>将另一个调用的方法移动到另一个服务类中,该服务类将通过Spring代理从原始服务类访问.
>将方法保留原样.声明服务类中的成员变量与服务类的接口类型相同,并使其成为@Autowired,这将为您提供对服务类的Spring代理对象的引用.然后,当您想要使用不同的事务行为调用您的方法时,请在该成员变量上而不是直接执行它,并且Spring事务代码将根据您的需要触发.

方法#1非常好,如果这两种方法实际上并不相关,因为它可以解决您的问题而不会混淆最终维护代码的人,并且无法忘记调用启用事务的方法.

方法#2通常是更好的选择,假设您的方法由于某种原因而全部在同一服务中,并且您不想真正将它们拆分出来.但是对于一个不理解Spring事务的皱纹的维护者而言,这是令人困惑的,你必须记住在你调用它的每个地方以这种方式调用它,所以这是有代价的.我通常愿意支付这个价格,以免不自然地分裂我的服务类,但一如既往,这取决于你的情况.

转载注明原文:spring – Grails服务交易行为 - 代码日志