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

查看:131
本文介绍了如何在Spring和GlassFish 5中执行分布式事务XA?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图创建一个包含两个REST Web服务的事务,其数据源指向相同的数据库。第一个名为 1 的服务使用Spring RestTemplate调用另一个名为 2 的Web服务。



为了实现事务,我使用了JNDI连接池,MySql JDBC驱动程序(版本5.1.35),JTA,XA,Spring和GlassFish 5 AppServer。

现在,我已经下载了Spring项目中的Maven依赖项,使用 JtaTransactionManager 定义了一个配置类,并将数据源和JTA属性配置为 application.yml 文件,如下面的代码所示:


配置类:




  @Configuration 
@EnableTransactionManagement
public class Transacciones {

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

}




application.yml文件



  spring:
数据源:
jndi-名称:jdbc / Prueba
driver-class-name:com.mysql.jdbc.Driver
$ b jta:
启用:true

我在GlassFish 5中配置了定义名为 jdbc / Prueba 的JDBC资源的JNDI数据源。使用 javax.sql.XADataSource 数据源名为 pruebaXA 的Connections pools页面:





在Web服务控制层 1 ,该方法使用Spring Framework的 RestTemplate 类调用服务 2 p>


服务1代码:




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

@Autowired
private JdbcTemplate objJdbcTemplate;


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

整型intRes1;
整型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 +));

返回数字;
} catch(Exception e){
throw new RuntimeException(e);
}
}
}




服务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 +));
返回intRes;
} catch(Exception e){
throw new RuntimeException(e);





$ p $如果这两个服务工作没有错误,没有问题。但是,当服务 1 下降时,服务 2 不知道错误并且不执行回滚。



我不知道是否需要在GlassFish 5或Spring程序中配置其他功能/选项。



我已经读过,在Spring中只需要一个 JtaTransactionManager bean,该框架执行与配置和使用JTA事务有关的所有工作。 Spring和JTA


JTA



现在,如果您仍然需要使用JTA,至少您的选择是您的到
使。有两种常见的情况:在重量级
应用程序服务器中使用JTA(它具有绑定到JavaEE服务器的
的所有令人讨厌的缺点),或者使用独立的JTA实现。
Spring通过PlatformTransactionManager实现
调用JtaTransactionManager为基于JTA的全局事务
实现提供支持。如果您在JavaEE应用程序
服务器上使用它,它将自动从JNDI中找到正确的
javax.transaction.UserTransaction引用。此外,
将尝试在9个不同的
应用程序服务器中查找特定于容器的
javax.transaction.TransactionManager引用,以查找更高级用例,如事务
暂停。在幕后,Spring会加载不同的
JtaTransactionManager子类,以利用不同服务器中特定的额外
功能,例如:
WebLogicJtaTransactionManager,WebSphereUowTransactionManager和
OC4JJtaTransactionManager。因此,如果您在Java EE应用程序服务器中,并且无法转义
,但希望使用Spring的JTA支持,那么很可能您
可以使用以下命名空间配置支持正确地(并自动)为
JtaTransactionManager工厂生产:

或者,您可以注册
JtaTransactionManager bean实例,如下所示:
$ b

b $ b

 返回新的JtaTransactionManager(); }不管怎样,JavaEE应用程序服务器的最终结果是您现在可以使用JTA来管理

感谢您的帮助和时间。

感谢您的帮助和时间。 class =h2_lin>解决方案


如何做分布式事务XA?



<如果您先调用REST或Web服务,然后再调用另一个,那么这两个操作都不会成为事务的一部分。要形成交易,这些操作必须开始交易或加入现有交易。要执行该事务,您的程序必须与事务监视器(TM)交互,例如 AT& T / Oracle Tuxedo (发布于80年代), X / Open XA标准(90年代发布)和基于JTA的系统。 p>

请注意基于TM的交易是如何工作的:


  • 使用XA数据源的事务基本上是一个调用两个不同数据库的数据库操作的程序。相同的程序(例如调用一个或多个bean中的方法)启动事务,对数据库执行一些操作并对另一个数据库执行其他操作。如果其中一个操作失败,则其他操作不会执行或被回滚。

  • 使用XA数据源和启用JTA的组件的事务 strong>基本上是一个将一个或多个数据库的操作与其他支持事务的操作相结合的程序。例如,您可以将数据库上的操作与内容存储库或基于网络的文件系统上的操作组合在一起。您可以定义在数据库操作失败时不对文件系统执行或回滚操作的事务。通过在事务监视器中定义操作和补偿,非事务性应用程序(如基于COBOL的程序)可以集成到事务中。 例如,针对web服务交易的提案,例如 WS-Transaction WS-Coordination 规范。有一个协调器像事务监视器一样工作。软件必须调用协调器来启动事务。交易中的每个参与者报告每项操作是成功还是失败。协调员根据结果调用其他操作或调用补偿。 现在,有一些关于软件的建议架构不依赖基于TM的交易。基于 CQRS Event Sourcing 使用萨格斯设计模式。如果您有兴趣定义一个调用两个REST服务的类似事务的操作,您可以考虑避免使用XA / JTA并编写一个Sagas。



    如何在Spring和GlassFish 5中执行分布式事务XA?您可以在Internet中查看许多教程。例如,


    • a 教程,它向您展示了三种用例:一种更新两个数据库,一个组合数据库操作和传出的JMS消息,另一个组合传入JMS消息和数据库操作。

    • a 视频描述如何使用JTA来管理Spring中的分布式事务

    • documentation



    如果两项服务无误地工作,则没有问题。但是,当服务 1 下降时,服务 2 不知道错误并且不执行回滚。

    这是正确的行为。当您调用REST / webservice时,由该REST / webservice执行的操作不会加入到事务中。如果调用服务失败,被调用的服务将不会注意到它,并且不会在数据库中回滚它们的操作。


    我不知道是否我需要在GlassFish 5或Spring程序中配置另一个功能/选项。


    没有。您只需配置XA数据源。 Spring将使用你的配置类和注解来自动地将你的应用程序在这些数据源上执行的操作加入到一个事务中。例如,如果你有一个调用多个方法的bean来执行一个或多个XA-datasources的操作,这些操作将会加入到一个事务中。



    然而,当你在另一个应用程序中调用REST / webservice中的方法时,该REST / webservice执行的数据库操作将不会加入到该事务中。

    I am trying to create a transaction comprising two REST web services, whose data source point to the same data base. The first service, named 1, invokes another web service named 2 using Spring RestTemplate.

    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.

    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:

    Configuration class:

    @Configuration
    @EnableTransactionManagement
    public class Transacciones {
    
        @Bean
         public PlatformTransactionManager platformTransactionManager(){ 
            return new JtaTransactionManager();
        }
    
    }
    

    application.yml file

    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.XADataSourcedatasource named pruebaXA:

    In the control layer of the web service 1, the method calls the service 2 using the RestTemplate class of Spring Framework:

    Service 1 code:

    @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:

    @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.

    I do not know if I need to configure another feature/option in the GlassFish 5, or in the Spring program.

    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 and JTA

    JTA

    Now, if you still need to use JTA, at least the choice is yours to make. 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. Spring provides support for JTA-based global transaction implementations through a PlatformTransactionManager implementation called JtaTransactionManager. If you use it on a JavaEE application server, it will automatically find the correct javax.transaction.UserTransaction reference from JNDI. 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. 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.

    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):

    Alternatively, you can register a JtaTransactionManager bean instance as appropriate, with no constructor arguments, like this:

    @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.

    Thanks for your help and time.

    解决方案

    How to do Distributed Transactions XA ?

    If you invoke first a REST or web service and then another one, both operations will not be part of a transaction. 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.

    Note how the TM-based transaction works:

    • A transaction using XA datasources is basically a program that invokes database operations on two different databases. The same program (e.g. invoking methods in one or more bean) starts the transaction, performs some operations on a database and performs other operations on another database. 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. 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.

    • A transaction integrating web-services requires an special handling. For instance, there is a proposal for webservice transactions such as the WS-Transaction and WS-Coordination specification. 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. Designs based on CQRS and Event Sourcing implement transactions using the Sagas design pattern. 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.

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

    You may check many tutorials in the 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.
    • a video describing how to manage distributed transactions in Spring with JTA
    • and the documentation from the 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.

    That is the correct behavior. When you invoke a REST/webservice, the operations performed by that REST/webservice do not join to the transaction. 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.

    No. You only have to configure the XA-datasources. Spring will use your configuration class and annotations to join automatically into a transaction the operations performed by your application on these datasources. 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.

    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.

    这篇关于如何在Spring和GlassFish 5中执行分布式事务XA?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆