什么是Grails"交易"服务?

sme*_*eeb 1 service grails transactions jta

我正在阅读关于服务的Grails文档,这些文档多次提到事务/事务性,但没有真正定义事务服务方法的真正含义.

鉴于服务的性质,它们经常需要交易行为.

这到底是什么意思?是交易方法只有那些使用JPA/JDBC来与关系数据库进行通信,或者说它们适用于任何由JTA覆盖?

是否有任何理由为什么我不会制作服务类@Transactional以防万一它发展到有一天使用交易?换句话说,是否存在使所有服务方法具有交易性能的性能问题?

Bur*_*ith 7

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

static transactional = false
Run Code Online (Sandbox Code Playgroud)

如果您尚未禁用与transactional属性的事务并且没有注释,则该服务的工作方式与使用Spring的注释进行注释相同.也就是说,在运行时,Spring会创建一个类的CGLIB代理,并将代理的实例注册为Spring bean,并将其委托给实际类的实例来执行数据库访问和业务逻辑.这允许代理拦截所有公共方法调用并启动新事务,加入现有事务,创建新事务等.

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

交易方法涉及小的性能损失,如果有大量呼叫和/或大量流量,这可能会累积.在代码运行之前,会启动一个事务(假设一个事务处于非活动状态),为此,必须从池中检索连接(DataSource)并配置为关闭自动提交,并进行各种事务设置(隔离,超时) ,readonly等)必须制作.但Grails DataSource实际上是围绕"真实"的智能包装器.在您启动查询之前,它不会获得真正的JDBC连接,因此在此之前缓存所有配置设置,然后在实际连接上"重放".如果该方法不执行任何数据库工作(因为它从来没有,或者因为它在db访问代码触发之前基于某些条件提前退出),那么基本上没有数据库成本.但如果确实如此,那么事情就会按预期发挥作用.

不要依赖于这种DataSource代理逻辑 - 最好明确哪些服务是事务性的,哪些不是事务性的,并且在每个服务中哪些方法是事务性的,哪些不是.执行此操作的最佳方法是根据需要注释方法,或者如果所有方法都使用相同的设置,则在类级别添加单个注释.

您可以在我关于Grails中的交易的演讲中获得更多信息.


Jos*_*ore 5

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

通常在 Grails 中,atransaction与数据库连接或休眠会话的事务状态有关。尽管它可以是 JTA 管理的任何具有正确 Spring 配置的东西。

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