简体   繁体   English

如何在Spring和GlassFish 5中进行分布式事务XA?

[英]How to do Distributed Transactions XA in Spring and GlassFish 5?

I am trying to create a transaction comprising two REST web services, whose data source point to the same data base. 我正在尝试创建一个包含两个REST Web服务的事务,其数据源指向相同的数据库。 The first service, named 1 , invokes another web service named 2 using Spring RestTemplate. 名为1的第一个服务使用Spring RestTemplate调用另一个名为2 Web服务。

To implement the transaction I am using a JNDI connection pool, the MySql JDBC driver (version 5.1.35), JTA, XA, Spring and the GlassFish 5 AppServer. 为了实现事务,我使用的是JNDI连接池,MySql JDBC驱动程序(版本5.1.35),JTA,XA,Spring和GlassFish 5 AppServer。

Now, I have downloaded the maven dependencies in the Spring project, defined a configuration class using JtaTransactionManager , and configured the datasource and JTA properties in an application.yml file, like in the following code: 现在,我已经在Spring项目中下载了maven依赖项,使用JtaTransactionManager定义了一个配置类,并在application.yml文件中配置了数据源和JTA属性,如下面的代码所示:

Configuration class: 配置类:

@Configuration
@EnableTransactionManagement
public class Transacciones {

    @Bean
     public PlatformTransactionManager platformTransactionManager(){ 
        return new JtaTransactionManager();
    }

}

application.yml file application.yml文件

spring:
  datasource:
    jndi-name: jdbc/Prueba  
    driver-class-name: com.mysql.jdbc.Driver

  jta:
    enabled: true                               

I configured the JNDI datasource in GlassFish 5 defining a "JDBC Resource" named jdbc/Prueba in the "Connections pools" page using a javax.sql.XADataSource datasource named pruebaXA : 我在GlassFish 5中配置了JNDI数据源,使用名为pruebaXAjavax.sql.XADataSource数据源在“Connections pools”页面中定义名为jdbc/Prueba的“JDBC资源”:

GlassFish,连接池

In the control layer of the web service 1 , the method calls the service 2 using the RestTemplate class of Spring Framework: 在Web服务1的控制层中,该方法使用Spring Framework的RestTemplate类调用服务2

Service 1 code: 服务1代码:

@RestController
@RequestMapping("/servicio")
@EnableTransactionManagement
public class a {

    @Autowired
    private JdbcTemplate objJdbcTemplate;


    @Transactional(rollbackFor = RuntimeException.class)
    @GetMapping("/1")
    public Integer getValor(){
        try{
            int numero;
            int n=50;
            RestTemplate restTemplate = new RestTemplate();

            Integer intRes1;
            Integer intRes2;
            numero = (int) (Math.random() * n) + 1;

            intRes2 = restTemplate.postForObject("http://localhost:8080/servicio2-1.0-SNAPSHOT/servicio/2",numero,Integer.class);

            intRes1=objJdbcTemplate.update("INSERT INTO A VALUES(" +numero + ")");

            return numero;
        }catch(Exception e){
            throw new RuntimeException(e);
        }
    }
}

Service 2 code: 服务2代码:

@RestController
@RequestMapping("/servicio")
public class a {

    @Autowired
    private JdbcTemplate objJdbcTemplate;

    @Transactional(rollbackFor = RuntimeException.class)
    @PostMapping("/2")
    public Integer getValor(@RequestBody Integer intNum){
        try{
            Integer intRes;

            intRes=objJdbcTemplate.update("INSERT INTO B VALUES(" + intNum + ")");
            return intRes;
        }catch(Exception e){
            throw new RuntimeException(e);
        }
    }
}

If the two services work without errors, there is not problem. 如果两个服务没有错误,则没有问题。 However, when the service 1 falls, the service 2 does not know about the error and does not do the rollback. 但是,当服务1下降时,服务2不知道错误并且不进行回滚。

I do not know if I need to configure another feature/option in the GlassFish 5, or in the Spring program. 我不知道是否需要在GlassFish 5或Spring程序中配置另一个功能/选项。

I have read that in Spring only needs a JtaTransactionManager bean and the framework performs all the work related to configure and use JTA-transactions. 我已经读过,在Spring中只需要一个JtaTransactionManager bean,框架执行与配置和使用JTA事务相关的所有工作。 Spring and JTA 春天和JTA

JTA JTA

Now, if you still need to use JTA, at least the choice is yours to make. 现在,如果您仍然需要使用JTA,至少可以选择您的选择。 There are two common scenarios: using JTA in a heavyweight application server (which has all the nasty disadvantages of being tied to a JavaEE server), or using a standalone JTA implementation. 有两种常见的情况:在重量级应用程序服务器中使用JTA(具有绑定到JavaEE服务器的所有令人讨厌的缺点),或使用独立的JTA实现。 Spring provides support for JTA-based global transaction implementations through a PlatformTransactionManager implementation called JtaTransactionManager. Spring通过名为JtaTransactionManager的PlatformTransactionManager实现为基于JTA的全局事务实现提供支持。 If you use it on a JavaEE application server, it will automatically find the correct javax.transaction.UserTransaction reference from JNDI. 如果在JavaEE应用程序服务器上使用它,它将自动从JNDI中找到正确的javax.transaction.UserTransaction引用。 Additionally, it will attempt to find the container-specific javax.transaction.TransactionManager reference in 9 different application servers for more advanced use cases like transaction suspension. 此外,它将尝试在9个不同的应用程序服务器中查找特定于容器的javax.transaction.TransactionManager引用,以获取更高级的用例,例如事务暂停。 Behind the scenes, Spring loads different JtaTransactionManager subclasses to take advantage of specific, extra features in different servers when available, for example: WebLogicJtaTransactionManager, WebSphereUowTransactionManager and OC4JJtaTransactionManager. 在幕后,Spring加载了不同的JtaTransactionManager子类,以便在可用时利用不同服务器中的特定额外功能,例如:WebLogicJtaTransactionManager,WebSphereUowTransactionManager和OC4JJtaTransactionManager。

So, if you're inside a Java EE application server, and can't escape, but want to use Spring's JTA support, then chances are good that you can use the following namespace configuration support to factory a JtaTransactionManager correctly (and automatically): 因此,如果您在Java EE应用程序服务器中,并且无法转义,但想要使用Spring的JTA支持,那么您可以使用以下命名空间配置支持来正确(并自动)生成JtaTransactionManager:

Alternatively, you can register a JtaTransactionManager bean instance as appropriate, with no constructor arguments, like this: 或者,您可以根据需要注册JtaTransactionManager bean实例,不带构造函数参数,如下所示:

@Bean public PlatformTransactionManager platformTransactionManager(){ @Bean public PlatformTransactionManager platformTransactionManager(){

 return new JtaTransactionManager(); } Either way, the end result in a JavaEE application server is that you can now use JTA to manage 

your transactions in a unified manner thanks to Spring. 感谢Spring,你的交易是统一的。

Thanks for your help and time. 谢谢你的帮助和时间。

How to do Distributed Transactions XA ? 如何进行分布式事务XA?

If you invoke first a REST or web service and then another one, both operations will not be part of a transaction. 如果首先调用REST或Web服务,然后再调用另一个,则两个操作都不会成为事务的一部分。 To form a transaction, these operations must "start" a transaction or be "joined" to an existing one. 为了形成交易,这些操作必须“开始”交易或“加入”现有交易。 To execute that transaction, your program must interact with a transaction monitor (TM) such as the proposed by AT&T/Oracle Tuxedo (released in the 80s), the X/Open XA standard (released in the 90s) and the JTA-based systems . 要执行该事务,您的程序必须与事务监视器(TM)交互,例如AT&T / Oracle Tuxedo (80年代发布), X / Open XA标准 (90年代发布)和基于JTA的系统。

Note how the TM-based transaction works: 请注意基于TM的事务如何工作:

  • A transaction using XA datasources is basically a program that invokes database operations on two different databases. 使用XA数据源的事务基本上是一个在两个不同数据库上调用数据库操作的程序。 The same program (eg invoking methods in one or more bean) starts the transaction, performs some operations on a database and performs other operations on another database. 相同的程序(例如,调用一个或多个bean中的方法)启动事务,对数据库执行某些操作并对另一个数据库执行其他操作。 If one of the operation fails, the other operations are not performed or are rollbacked. 如果其中一个操作失败,则不执行其他操作或回滚操作。

  • A transaction using XA datasources and JTA-enabled components is basically a program that combines operations on one or more databases with other transaction-enabled operations. 使用XA数据源和支持JTA的组件的事务基本上是一个程序,它将一个或多个数据库上的操作与其他启用事务的操作相结合。 For instance, you can combine operations on a database with operations on a content repository or a network-based file system. 例如,您可以将数据库上的操作与内容存储库或基于网络的文件系统上的操作相结合。 You can define transactions that, when a database operation fails, does not perform or rollbacks operations on the file system. 您可以定义在数据库操作失败时不对文件系统执行或回滚操作的事务。 Non-transactional applications such as COBOL-based programs can be integrated in a transaction by defining operations and compensations in the transaction monitor. 通过在事务监视器中定义操作和补偿,可以将非事务性应用程序(如基于COBOL的程序)集成到事务中。

  • A transaction integrating web-services requires an special handling. 集成Web服务的事务需要特殊处理。 For instance, there is a proposal for webservice transactions such as the WS-Transaction and WS-Coordination specification. 例如,有一个Web服务事务的提议,例如WS-TransactionWS-Coordination规范。 There is a coordinator that works like the transaction monitor. 有一个协调器 ,它像事务监视器一样工作。 The software must invoke the coordinator to start the transaction. 软件必须调用协调器才能启动事务。 Each participant in the transaction reports if each operation is successful or failed. 事务中的每个参与者报告每个操作是成功还是失败。 The coordinator invokes the other operations or invokes the compensations according to the results. 协调器根据结果调用其他操作或调用补偿。

Nowadays, there are some proposals for software architecture that do not rely on TM-based transactions. 如今,有一些软件架构的提议不依赖于基于TM的事务。 Designs based on CQRS and Event Sourcing implement transactions using the Sagas design pattern . 基于CQRSEvent Sourcing设计使用Sagas设计模式实现事务。 If you are interested on defining a transaction-like operation that invokes two REST services, you may consider to avoid the XA/JTA and program a Sagas. 如果您对定义调用两个REST服务的类事务操作感兴趣,可以考虑避免使用XA / JTA并编写Sagas。

How to do Distributed Transactions XA in Spring and GlassFish 5? 如何在Spring和GlassFish 5中进行分布式事务XA?

You may check many tutorials in the Internet. 您可以在Internet上查看许多教程。 For instance, 例如,

  • a tutorial that shows you three use cases: one updating two databases, one combining database operations and outgoing JMS-messages, and another one combining incoming JMS messages and database operations. 一个教程 ,向您展示三个用例:一个更新两个数据库,一个组合数据库操作和传出JMS消息,另一个组合传入JMS消息和数据库操作。
  • a video describing how to manage distributed transactions in Spring with JTA 一个视频,描述了如何使用JTA在Spring中管理分布式事务
  • and the documentation from the Spring Framework. 以及Spring Framework的文档

If the two services work without errors, there is not problem. 如果两个服务没有错误,则没有问题。 However, when the service 1 falls, the service 2 does not know about the error and does not do the rollback. 但是,当服务1下降时,服务2不知道错误并且不进行回滚。

That is the correct behavior. 这是正确的行为。 When you invoke a REST/webservice, the operations performed by that REST/webservice do not join to the transaction. 调用REST / Web服务时,该REST / Web服务执行的操作不会加入事务。 If the invoking service fails, the invoked service will not notice it and will not rollback their operations in the database. 如果调用服务失败,则调用的服务将不会注意到它,也不会回滚它们在数据库中的操作。

I do not know if I need to configure another feature/option in GlassFish 5, or in the Spring program. 我不知道是否需要在GlassFish 5或Spring程序中配置另一个功能/选项。

No. You only have to configure the XA-datasources. 不需要。您只需配置XA数据源。 Spring will use your configuration class and annotations to join automatically into a transaction the operations performed by your application on these datasources. Spring将使用您的配置类和注释将应用程序在这些数据源上执行的操作自动连接到事务中。 For instance, if you have a bean that invokes multiple methods that performs operations on one or more XA-datasources, these operations will join into a transaction. 例如,如果您有一个bean调用多个方法来对一个或多个XA数据源执行操作,那么这些操作将加入到一个事务中。

However, when you invoke a method in REST/webservice in another application, the database operations performed by that REST/webservice will not join to the transaction. 但是,当您在另一个应用程序中调用REST / webservice中的方法时,该REST / Web服务执行的数据库操作将不会加入该事务。

rest web services (http based) are non-transactional by their nature (they are http based). 其余的Web服务(基于http)本质上是非事务性的(它们是基于http的)。 you have made each method/operation transactional, but they do not share any state between the resources (rest operations). 您已经使每个方法/操作都是事务性的,但它们不共享资源之间的任何状态(休息操作)。 generally - you can have XA transactions over database or mesaging, not over http calls. 通常 - 您可以通过数据库或消息传递进行XA事务,而不是通过http调用。

intRes2 = restTemplate.postForObject("http://localhost:8080/servicio2-1.0-
SNAPSHOT/servicio/2",numero,Integer.class);

Calling a remote web service is without any transaction context. 调用远程Web服务没有任何事务上下文。 If you need to maintains transaction between services, call the secord service as EJB (or as an injected managed bean) 如果需要维护服务之间的事务,请将secord服务作为EJB(或作为注入的托管bean)调用

Basically: using http-based rest services - forget any transactions between them. 基本上:使用基于http的休息服务 - 忘记它们之间的任何交易。 The protocol (HTTP) is not built for that. 协议(HTTP)不是为此而构建的。

The only thing I've seen transactional is SOAP with WS-RM extension (SOAP with reliable messaging)., however it is not very easy to setup (read: it can be nightmare to make it work when you don't know what are you doing) and not all WS frameworks support it. 我唯一看到事务性的是具有WS-RM扩展的SOAP(带有可靠消息传递的SOAP)。但是它设置起来不是很容易(阅读:当你不知道什么是它时,它可能是噩梦你正在做)并不是所有的WS框架都支持它。

When you really need reliable delivery between web services, there's a way. 当您真正需要在Web服务之间可靠交付时,有一种方法。 what is comonly used to achieve assured delivery is messaging with idempotent services ( https://en.m.wikipedia.org/wiki/Idempotence ) with store-and-forward pattern. 通常用于实现有保证的交付的是具有存储转发模式的幂等服务( https://en.m.wikipedia.org/wiki/Idempotence )的消息传递。 In simple terms - service 1 stores a JMS message to a queue and there's a processor (MDB) which calls service 2. (yes, calling a remote web service it may happen that the service 2 will receive a message multiple times. Indempotency is a way how to deal with it.) 简单来说 - 服务1将JMS消息存储到队列中,并且存在调用服务2的处理器(MDB)。(是的,调用远程Web服务可能会发生服务2将多次接收消息。不约束是一个如何处理它。)

Transactions across REST services are supported by http://www.atomikos.com http://www.atomikos.com支持跨REST服务的事务

Cheers 干杯

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

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