Grails @Transactional 与 Spring @Transactional 注释之间的差异

Posted

技术标签:

【中文标题】Grails @Transactional 与 Spring @Transactional 注释之间的差异【英文标题】:Differences between the Grails @Transactional vs. the Spring @Transactional annotations 【发布时间】:2014-06-30 21:20:04 【问题描述】:

Grails 中有一个要点Declarative Transactions。它说:

grails.transaction.Transactional 注解最早是在 Grails 2.3 中引入的。在 2.3 之前,使用了 Spring 的 @Transactional 注解。

但我似乎无法找出这两个注释之间的主要区别是什么。为什么在以后的版本中没有使用 Spring 的注解?

【问题讨论】:

【参考方案1】:

我想解决这个评论“但是,在 2.3 中,团队认为引入一个新注释是个好主意(我个人不同意),它不仅可以应用于服务,还可以应用于控制器。”

引入可用于控制器和服务的注解从来不是 Grails 团队的主要意图。我们的主要目的是引入一个 AST 转换,它消除了对代理的需求,并且比 Spring 的 @Transactional 性能更好。 Grails 的 @Transactional 将处理事务的必要逻辑直接连接到字节码中,不需要代理,因此我们觉得它比 Spring 的版本更好。

它也适用于控制器的事实仅仅是我们发现的上述副作用的一个副作用。话虽如此,根据我们的经验,太多的 Grails 用户在使用控制器时没有正确划分他们的事务边界。如果您将控制器操作标记为只读,那么 Hibernate 不需要对您在该操作范围内执行的任何查询执行脏检查。这极大地提高了 Grails 应用程序的性能,并且可能是一件好事。

我们绝对鼓励将逻辑分离到服务中,但是如果您考虑以下简单的示例:

  @Transactional(readOnly=true)
  def show(Long id) 
       respond Foo.get(id)
  

为这种微不足道的操作引入服务是大材小用,但如果您不使用只读事务划分查询,那么 Hibernate 会对实例执行脏检查,这会损害性能。

22/02/16 更新:从 Grails 3.1 开始,Spring 版本被视为已弃用,默认情况下处于禁用状态(如果需要,您仍然可以重新启用)

【讨论】:

Graeme,感谢您详细了解它现在出现在控制器中的原因。从这个角度来看,这是有道理的,但它仍然被大量滥用。特别是对于不熟悉 Spring 并且不理解为什么使用 Service 有意义的新用户。您的示例很好地说明了为什么理解所使用的技术对于做出正确决策很重要,但对于完全不熟悉 Grails 的人来说,他们只会遵循他们所看到的模式。 我仍然认为从长远来看需要将注意力转移到服务上,这样做不会损害性能,即使是简单的事情。我完全理解这不是一个容易解决的问题,看到使用脚手架创建适当的服务也许是我的梦想。现在,我们都可以尝试互相教育。再次,非常感谢您在这里的回应和洞察力。 @Graeme 当您说“如果您将控制器操作标记为只读,则 Hibernate 不需要对您在该操作范围内执行的任何查询执行脏检查”。因此,当您从操作调用服务方法时会发生什么,而该操作又具有其他事务属性。是否被调用方法的事务行为覆盖???【参考方案2】:

与 Grails 2.3 版本的注解的另一个区别是,如果您在同一服务上从方法 A 调用方法 B,则方法 B 上的事务属性将被兑现。使用 Spring 注释,它不会被兑现,因为您绕过了应用事务的动态代理。

def methodA() 
    methodB()


@Transactional
def methodB() 
    ...

【讨论】:

是否有关于此行为的任何文档,或者这只是您观察到的?我观察到了同样的行为。【参考方案3】:

在 2.3 之前,使用 Spring 注释是因为它应用于服务。这只是简单的 Spring bean。然而,在 2.3 中,团队认为引入一个新的注释是一个好主意(我个人不同意),它不仅可以应用于服务,还可以应用于控制器。不同之处在于 Grails 2.3 版本的注解在 Grails 控制器的概念中执行了很多 AST 转换魔法。

希望对您有所帮助。

更新

从功能上讲,当应用于服务时,注释的 Grails 版本与 Spring 版本相同。虽然它的效率稍高一些,因为它是在编译时应用于您的代码的 AST 转换,而不是在运行时应用的代理。

【讨论】:

谢谢,很高兴知道,我也反对在控制器中使用事务注释。 欢迎您。每当我看到新用户只是遵循现在在控制器上使用@Transaction 搭建脚手架设置的不良做法时,我都会不寒而栗。如果我有时间,我将恢复我的增强服务插件的工作,这可能会解决同样的问题,但会将控制权移回服务,但我不会屏住呼吸。【参考方案4】:

为什么在以后的版本中没有使用 spring 的注解??

您仍然可以使用 Spring 注解。 Grails 版本更灵活,性能更高,因为我们可以在编译时设置很多逻辑,但 Spring 版本仍然存在,并且仍然像以前一样运行。

【讨论】:

【参考方案5】:

@PrakashJoshi 说:

那么当您从操作调用服务方法时会发生什么,该操作又具有其他事务属性。它是否被被调用方法的事务行为覆盖???

这取决于您将事务传播行为设置为什么(可在注释上设置)。 PROPAGATION_REQUIRED(默认)将继续一个现有的,但 PROPAGATION_NEW 将启动一个新的,暂停当前的。

【讨论】:

【参考方案6】:

你仍然可以使用spring注解,但grails版本更快,更了解框架。

我强烈建议你使用 grails 版本。

【讨论】:

以上是关于Grails @Transactional 与 Spring @Transactional 注释之间的差异的主要内容,如果未能解决你的问题,请参考以下文章

如何加快 Grails 测试执行

事务与锁当Transactional遇上synchronized

@Transactional 与 JPA 和 Hibernate 有啥用?

Spring @Transactional on 类与方法

grails数据库配置的问题

@Transactional 注释与 saveAndFlush 一起使用?