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

J. *_*bel 4 java spring web-services glassfish

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

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

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

配置类:

@Configuration
@EnableTransactionManagement
public class Transacciones {

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

}
Run Code Online (Sandbox Code Playgroud)

application.yml文件

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

  jta:
    enabled: true                               
Run Code Online (Sandbox Code Playgroud)

我在GlassFish 5中配置了JNDI数据源,并jdbc/Prueba使用javax.sql.XADataSource名为的数据源定义了在“连接池”页面中命名的“ JDBC资源” pruebaXA

GlassFish,连接池

在Web服务的控制层中1,该方法2使用RestTemplateSpring Framework 的类调用服务:

服务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);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

服务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);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

如果两个服务均正常运行,则不会出现问题。但是,当服务1崩溃时,该服务将2不知道该错误,并且不会进行回滚。

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

我已经读到在Spring中只需要一个JtaTransactionManagerbean,并且框架执行与配置和使用JTA事务有关的所有工作。春季和JTA

日本旅游协会

现在,如果仍然需要使用JTA,则至少要由您决定。有两种常见的方案:在重量级的应用程序服务器中使用JTA(具有绑定到JavaEE服务器的所有弊端),或使用独立的JTA实现。Spring通过称为JtaTransactionManager的PlatformTransactionManager实现为基于JTA的全局事务实现提供支持。如果在JavaEE应用程序服务器上使用它,它将从JNDI自动找到正确的javax.transaction.UserTransaction引用。此外,它将尝试在9个不同的应用程序服务器中查找特定于容器的javax.transaction.TransactionManager参考,以获取更高级的用例,例如事务暂停。在幕后

因此,如果您位于Java EE应用程序服务器中,并且无法逃脱,但想使用Spring的JTA支持,则很有可能可以使用以下名称空间配置支持来正确地(并自动地)构建JtaTransactionManager:

另外,您可以在没有构造函数参数的情况下,适当地注册JtaTransactionManager bean实例,如下所示:

@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
Run Code Online (Sandbox Code Playgroud)

借助Spring,您可以统一地进行交易。

感谢您的帮助和时间。

Jai*_*ime 5

如何进行XA分布式事务?

如果先调用REST或Web服务,然后再调用另一个,则这两个操作都不是事务的一部分。要形成交易,这些操作必须“启动”交易或“加入”现有交易。要执行该事务,您的程序必须与事务监视器(TM)进行交互,例如AT&T / Oracle Tuxedo(在80年代发行的),X / Open XA标准(在90年代发行的)以及基于JTA的系统中提出的交易

请注意基于TM的事务的工作方式:

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

  • 使用XA数据源和启用JTA的组件进行的事务基本上是一种程序,该程序将一个或多个数据库上的操作与其他启用事务的操作相结合。例如,您可以将数据库上的操作与内容存储库或基于网络的文件系统上的操作结合起来。您可以定义在数据库操作失败时不会在文件系统上执行或回滚操作的事务。通过在事务监视器中定义操作和补偿,可以将非事务应用程序(例如基于COBOL的程序)集成到事务中。

  • 集成Web服务的事务需要特殊处理。例如,有一个针对Web服务事务的提议,例如WS-TransactionWS-Coordination规范。有一个像事务监视器一样的协调器。软件必须调用协调器才能启动事务。交易中的每个参与者都会报告每个操作是成功还是失败。协调器根据结果调用其他操作或调用补偿。

如今,有一些不依赖于基于TM的事务的软件体系结构提案。基于CQRS事件源设计使用Sagas设计模式实现事务。如果您对定义调用两个REST服务的类似事务的操作感兴趣,则可以考虑避免使用XA / JTA并编写Sagas。

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

您可以在Internet上查看许多教程。例如,

  • 一本教程,向您展示了三种用例:一种更新两个数据库,一种结合数据库操作和传出JMS消息,另一种结合传入JMS消息和数据库操作。
  • 一段视频,描述了如何使用JTA在Spring中管理分布式事务
  • 以及Spring框架中的文档

如果两个服务均正常运行,则不会出现问题。但是,当服务1崩溃时,该服务将2不知道该错误,并且不会进行回滚。

那是正确的行为。调用REST / Web服务时,该REST / Web服务执行的操作不会加入事务。如果调用服务失败,则调用的服务将不会注意到它,也不会回滚其在数据库中的操作。

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

不需要。您只需配置XA数据源。Spring将使用您的配置类和注释将应用程序在这些数据源上执行的操作自动加入到事务中。例如,如果您有一个Bean调用多个对一个或多个XA数据源执行操作的方法,则这些操作将加入事务。

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