什么是 Grails "transactional" 服务?

What is a Grails "transactional" service?

我正在阅读 services 上的 Grails 文档,其中多次提到 transactions/transactionality,但没有真正定义 事务性 服务方法的真正含义.

Given the nature of services, they frequently require transactional behaviour.

这到底是什么意思? 事务性 方法仅是那些使用 JPA/JDBC 与关系数据库通信的方法,还是它们适用于 JTA 涵盖的任何内容?

我有什么理由不提供服务 class @Transactional 以防有一天它发展到使用交易?换句话说,使所有服务方法都具有事务性是否存在性能问题?

首先,如果您的性能问题是由于您的服务是事务性的,那么您已经达到了必杀技。我这样说是因为在这成为主要(甚至次要)问题之前很久,您的应用程序中就会有很多其他瓶颈。所以,别担心。

通常在 Grails 中,transaction 与数据库连接或休眠会话的事务状态相关。尽管它可以是 JTA 通过适当的 Spring 配置管理的任何东西。

简单来说,它通常意味着(默认情况下)数据库事务。

Grails 服务默认是事务性的 - 如果您不希望服务是事务性的,您需要删除所有 @Transactional 注释(Grails 的 @grails.transaction.Transactional 和 Spring的 @org.springframework.transaction.annotation.Transactional) 并添加

static transactional = false

如果您没有禁用 transactional 属性 的交易并且没有注释,则该服务的工作方式与使用 Spring 的注释一样。也就是说,在运行时 Spring 创建一个 class 的 CGLIB 代理并将代理的实例注册为 Spring bean,然后它委托给实际 class 做数据库访问和你的业务逻辑。这让代理拦截所有 public 方法调用并开始新事务、加入现有事务、创建新事务等。

较新的 Grails 注释具有与 Spring 注释相同的所有设置,但工作方式略有不同。不是触发单个代理的创建,而是在编译期间通过 AST 转换重写每个方法,本质上是为每个方法创建一个迷你代理(这显然是一种简化)。这更好,因为数据库访问和事务语义是相同的,但是如果您从另一个使用不同设置注释的注释方法调用一个注释方法,则将遵守不同的设置。但是使用代理,它是在委托实例内部直接调用,代理被绕过。由于代理具有创建新事务或使用其他不同设置的所有逻辑,因此这两种方法将使用第一种方法的设置。使用 Grails 注释,每个方法都按预期工作。

事务方法对性能的影响很小,如果有很多调用 and/or 很多流量,这种情况就会累积。在你的代码运行之前,一个事务被启动(假设一个不活跃)并且要做到这一点,必须从池(数据源)中检索一个连接并配置为关闭自动提交,并进行各种事务设置(隔离,超时, readonly, 等) 必须制作。但 Grails DataSource 实际上是 "real" 的智能包装器。在您开始查询之前,它不会获得真正的 JDBC 连接,因此所有配置设置都被缓存到那时,然后 "replayed" 在真正的连接上。如果该方法不做任何数据库工作(因为它从不做,或者因为它在数据库访问代码触发之前根据某些条件提前退出),那么基本上没有数据库成本。但如果确实如此,那么事情就会按预期进行。

不要依赖此数据源代理逻辑 - 最好明确说明哪些服务是事务性的,哪些不是,以及在每个服务中哪些方法是事务性的,哪些不是。执行此操作的最佳方法是根据需要对方法进行注释,或者如果所有方法都使用相同的设置,则在 class 级别添加单个注释。

您可以在 this talk 我做的有关 Grails 事务的文章中获得更多信息。