简体   繁体   English

什么是Grails的“交易”服务?

[英]What is a Grails “transactional” service?

I'm reading the Grails docs on services which make numerous mention of transactions/transactionality, but without really defining what a transactional service method really is. 我正在阅读有关服务的Grails文档,该文档大量提及了事务/事务性,但并未真正定义事务服务方法的真正含义。

Given the nature of services, they frequently require transactional behaviour. 鉴于服务的性质,它们经常需要交易行为。

What exactly does this mean? 这到底是什么意思? Are transactional methods only those that use JPA/JDBC to communicate with a relational DB, or do they apply to anything covered by JTA? 事务方法是仅使用JPA / JDBC与关系数据库进行通信的事务方法,还是适用于JTA涵盖的所有事务

Is there any reason why I just wouldn't make a service class @Transactional in case it evolves to some day use a transaction? 有什么理由为什么我不会将服务类@Transactional为万一它演变为某天使用事务? In other words, are there performance concerns to making all service methods transactional? 换句话说,是否存在使所有服务方法都具有事务性的性能问题?

Grails services are transactional by default - if you don't want a service to be transactional, you need to remove all @Transactional annotations (both Grails' @grails.transaction.Transactional and Spring's @org.springframework.transaction.annotation.Transactional ) and add Grails服务默认情况下是事务性的-如果您不希望服务是事务性的,则需要删除所有@Transactional批注(Grails的@grails.transaction.Transactional和Spring的@org.springframework.transaction.annotation.Transactional )并添加

static transactional = false

If you haven't disabled transactions with the transactional property and have no annotations, the service works the same as if it were annotated with Spring's annotation. 如果您没有使用transactional属性禁用事务并且没有注释,则该服务的工作方式与使用Spring注释进行注释的服务相同。 That is, at runtime Spring creates a CGLIB proxy of your class and registers an instance of the proxy as the Spring bean, and it delegates to an instance of your actual class to do the database access and your business logic. 也就是说,在运行时,Spring将创建您的类的CGLIB代理,并将该代理的实例注册为Spring Bean,并将其委托给实际类的实例以进行数据库访问和业务逻辑。 This lets the proxy intercept all public method calls and start a new transaction, join an existing one, create a new one, etc. 这使代理可以拦截所有公共方法调用并启动新事务,加入现有事务,创建新事务等。

The newer Grails annotation has all of the same settings as the Spring annotation, but it works a bit differently. 较新的Grails批注具有与Spring批注相同的所有设置,但工作方式略有不同。 Instead of triggering the creation of a single proxy, each method is rewritten by an AST transform during compilation, essentially creating a mini proxy for each method (this is obviously a simplification). 编译过程中,每个方法都由AST转换重写,而不是触发单个代理的创建,本质上为每个方法创建了一个迷你代理(这显然是一种简化)。 This is better because the database access and transaction semantics are the same, but if you call one annotated method from another annotated with different settings, the different settings will be respected. 这样做更好,因为数据库访问和事务语义相同,但是如果您从另一个使用不同设置进行注释的方法中调用一个被注释的方法,则将遵循不同的设置。 But with a proxy, it's a direct call inside the delegate instance, and the proxy is bypassed. 但是对于代理,它是委托实例内部的直接调用,并且代理被绕过。 Since the proxy has all of the logic to create a new transaction or use other different settings, the two methods will use the first method's settings. 由于代理具有创建新事务或使用其他不同设置的所有逻辑,因此这两种方法将使用第一种方法的设置。 With the Grails annotation every method works as expected. 使用Grails批注,每种方法都能按预期工作。

There is a small performance hit involved for transactional methods, and this can accumulate if there are a lot of calls and/or a lot of traffic. 事务处理方法对性能的影响很小,如果有大量的调用和/或大量的通信量,这会累积。 Before your code runs, a transaction is started (assuming one isn't active) and to do this, a connection must be retrieved from the pool (DataSource) and configured to turn off autocommit, and make the various transaction settings (isolation, timeout, readonly, etc.) have to be made. 在代码运行之前,将启动一个事务(假设其中一个未处于活动状态),并且为此必须从池(DataSource)中检索连接并将其配置为关闭自动提交,并进行各种事务设置(隔离,超时)。 ,只读等)。 But the Grails DataSource is actually a smart wrapper around the "real" one. 但是Grails数据源实际上是围绕“真实”数据库的智能包装。 It doesn't get a real JDBC Connection until you start a query, so all of the configuration settings are cached until then, and then "replayed" on the real connection. 在启动查询之前,它不会获得真正的JDBC连接,因此所有配置设置都将一直缓存到那时,然后在真正的连接上“重播”。 If the method doesn't do any database work (either because it never does, or because it exits early based on some condition before the db access code fires), then there's basically no database cost. 如果该方法不执行任何数据库工作(或者因为它从不执行,或者因为它在数据库访问代码触发之前基于某种条件而提前退出),那么基本上没有数据库成本。 But if it does, then things work as expected. 但是,如果确实如此,那么事情将按预期进行。

Don't rely on this DataSource proxying logic though - it's best to be explicit about which services are transactional and which aren't, and within each service which methods are transactional and which aren't. 但是,不要依赖于这种DataSource代理逻辑-最好明确说明哪些服务是事务性的,哪些不是事务性的,以及在每个服务中哪些方法是事务性的,哪些不是事务性的。 The best way to do this is by annotating methods as needed, or adding a single annotation at the class level if all methods use the same settings. 最好的方法是根据需要对方法进行注释,或者,如果所有方法都使用相同的设置,则在类级别添加单个注释。

You can get more info in this talk I did about transactions in Grails. 您可以在我所做的有关Grails中事务的讨论中获得更多信息。

First, if your performance concerns are due to the fact your services are transactional then you have reached nirvana. 首先,如果您对性能的担心是由于您的服务具有事务性而造成的,那么您已经达到了必杀技。 I say this because there are going to be plenty of other bottle necks in your application long before this is a major (or even minor) concern. 我之所以这样说,是因为在这成为主要(甚至是次要)问题之前很久,您的应用程序中就会出现许多其他瓶颈。 So, don't fret about that. 所以,不要为此烦恼。

Typically in Grails a transaction relates to the transactional state of a database connection or hibernate session. 通常在Grails中, transaction与数据库连接或休眠会话的事务状态有关。 Though it could be anything managed by the JTA with the proper Spring configuration. 尽管可以由JTA通过适当的Spring配置来管理。

In simple terms, it's usually means (by default) a database transaction. 简单来说,(默认情况下)通常意味着数据库事务。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM