如何在 Spring 和 GlassFish 5 中执行分布式事务 XA?
How to do Distributed Transactions XA in Spring and GlassFish 5?
我正在尝试创建一个包含两个 REST Web 服务的事务,它们的数据源指向同一个数据库。第一个服务名为 1
,使用 Spring RestTemplate.
调用另一个名为 2
的 Web 服务
为了实现事务,我使用了 JNDI 连接池、MySql JDBC 驱动程序(版本 5.1.35)、JTA、XA、Spring 和 GlassFish 5 AppServer .
现在,我已经在 Spring 项目中下载了 Maven 依赖项,使用 JtaTransactionManager
定义了一个配置 class,并在 application.yml
中配置了数据源和 JTA 属性] 文件,如以下代码:
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
我在 GlassFish 5 中配置了 JNDI 数据源,在 "Connections pools" 页面中使用名为 pruebaXA
的 javax.sql.XADataSource
数据源定义了一个名为 jdbc/Prueba
的 "JDBC Resource":
在 Web 服务 1
的控制层中,该方法使用 Spring 框架的 RestTemplate
class 调用服务 2
:
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);
}
}
}
如果这两个服务没有错误,就没有问题。但是,当服务1
挂掉时,服务2
并不知道这个错误,也不做回滚。
我不知道是否需要在 GlassFish 5 或 Spring 程序中配置另一个 feature/option。
我读到在 Spring 中只需要一个 JtaTransactionManager
bean 并且框架执行与配置和使用 JTA 事务相关的所有工作。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.
感谢您的帮助和时间。
rest 网络服务(基于 http)本质上是非事务性的(它们基于 http)。您已经使每个 method/operation 成为事务性的,但它们不共享资源之间的任何状态(休息操作)。通常 - 您可以通过数据库或消息传递进行 XA 事务处理,而不是通过 http 调用。
intRes2 = restTemplate.postForObject("http://localhost:8080/servicio2-1.0-
SNAPSHOT/servicio/2",numero,Integer.class);
调用远程网络服务没有任何事务上下文。如果您需要维护服务之间的事务,请将 secord 服务作为 EJB(或作为注入的托管 bean)调用
基本上:使用基于 http 的休息服务 - 忘记它们之间的任何交易。协议 (HTTP) 不是为此而构建的。
我见过的唯一事务性的是带有 WS-RM 扩展的 SOAP(带有可靠消息传递的 SOAP)。但是它的设置不是很容易(阅读:当你不这样做时让它工作可能是一场噩梦不知道你在做什么)而且并不是所有的 WS 框架都支持它。
当您确实需要在 Web 服务之间进行可靠的交付时,有一种方法。通常用于实现可靠交付的是具有存储转发模式的幂等服务 (https://en.m.wikipedia.org/wiki/Idempotence) 的消息传递。简单来说 - 服务 1 将 JMS 消息存储到队列中,并且有一个调用服务 2 的处理器 (MDB)。(是的,调用远程 Web 服务时,服务 2 可能会多次接收消息。幂等性是如何处理它。)
支持跨 REST 服务的事务
干杯
How to do Distributed Transactions XA ?
如果您首先调用 REST 或 Web 服务,然后再调用另一个,则这两个操作都不会成为事务的一部分。要形成交易,这些操作必须 "start" 交易或 "joined" 现有交易。要执行该事务,您的程序必须与事务监视器 (TM) 交互,例如 AT&T/Oracle Tuxedo (released in the 80s), the X/Open XA standard (released in the 90s) and the JTA-based systems.
所提议的
注意基于 TM 的交易是如何工作的:
使用 XA 数据源的事务 基本上是一个在两个不同数据库上调用数据库操作的程序。同一个程序(例如,调用一个或多个 bean 中的方法)启动事务,对一个数据库执行某些操作,然后对另一个数据库执行其他操作。如果其中一个操作失败,则其他操作不执行或回滚。
使用 XA 数据源和支持 JTA 的组件的事务 基本上是一个将对一个或多个数据库的操作与其他支持事务的操作相结合的程序。例如,您可以将对数据库的操作与对内容存储库或基于网络的文件系统的操作结合起来。您可以定义在数据库操作失败时不执行或回滚文件系统操作的事务。通过在事务监视器中定义操作和补偿,可以将非事务应用程序(例如基于 COBOL 的程序)集成到事务中。
集成网络服务的事务需要特殊处理。例如,有 a proposal for webservice transactions 等 WS-Transaction 和 WS-Coordination 规范。有一个 coordinator 像事务监视器一样工作。软件必须调用协调器来启动事务。事务中的每个参与者都会报告每个操作是成功还是失败。协调器根据结果调用其他操作或调用补偿。
如今,有一些不依赖基于 TM 交易的软件架构建议。基于 CQRS and Event Sourcing implement transactions using the Sagas design pattern 的设计。如果您有兴趣定义调用两个 REST 服务的类似事务的操作,您可以考虑避免 XA/JTA 并编写一个 Sagas。
How to do Distributed Transactions XA in Spring and GlassFish 5?
你可以在网上查很多教程。例如,
- a tutorial 向您展示了三个用例:一个更新两个数据库,一个组合数据库操作和传出 JMS 消息,另一个组合传入 JMS 消息和数据库操作。
- a video 描述如何在 Spring 中使用 JTA
管理分布式事务
- 和来自 Spring 框架的 documentation。
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.
这是正确的行为。当您调用 REST/webservice 时,由 REST/webservice 执行的操作不会加入事务。如果调用服务失败,被调用服务不会注意到它,也不会回滚它们在数据库中的操作。
I do not know if I need to configure another feature/option in GlassFish 5, or in the Spring program.
没有。您只需配置 XA 数据源。 Spring 将使用您的配置 class 和注释自动将您的应用程序对这些数据源执行的操作加入到事务中。例如,如果您有一个调用多个方法的 bean,这些方法对一个或多个 XA 数据源执行操作,这些操作将加入一个事务。
但是,当您在另一个应用程序中调用 REST/webservice 中的方法时,该 REST/webservice 执行的数据库操作将不会加入事务。
我正在尝试创建一个包含两个 REST Web 服务的事务,它们的数据源指向同一个数据库。第一个服务名为 1
,使用 Spring RestTemplate.
2
的 Web 服务
为了实现事务,我使用了 JNDI 连接池、MySql JDBC 驱动程序(版本 5.1.35)、JTA、XA、Spring 和 GlassFish 5 AppServer .
现在,我已经在 Spring 项目中下载了 Maven 依赖项,使用 JtaTransactionManager
定义了一个配置 class,并在 application.yml
中配置了数据源和 JTA 属性] 文件,如以下代码:
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
我在 GlassFish 5 中配置了 JNDI 数据源,在 "Connections pools" 页面中使用名为 pruebaXA
的 javax.sql.XADataSource
数据源定义了一个名为 jdbc/Prueba
的 "JDBC Resource":
在 Web 服务 1
的控制层中,该方法使用 Spring 框架的 RestTemplate
class 调用服务 2
:
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);
}
}
}
如果这两个服务没有错误,就没有问题。但是,当服务1
挂掉时,服务2
并不知道这个错误,也不做回滚。
我不知道是否需要在 GlassFish 5 或 Spring 程序中配置另一个 feature/option。
我读到在 Spring 中只需要一个 JtaTransactionManager
bean 并且框架执行与配置和使用 JTA 事务相关的所有工作。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.
感谢您的帮助和时间。
rest 网络服务(基于 http)本质上是非事务性的(它们基于 http)。您已经使每个 method/operation 成为事务性的,但它们不共享资源之间的任何状态(休息操作)。通常 - 您可以通过数据库或消息传递进行 XA 事务处理,而不是通过 http 调用。
intRes2 = restTemplate.postForObject("http://localhost:8080/servicio2-1.0-
SNAPSHOT/servicio/2",numero,Integer.class);
调用远程网络服务没有任何事务上下文。如果您需要维护服务之间的事务,请将 secord 服务作为 EJB(或作为注入的托管 bean)调用
基本上:使用基于 http 的休息服务 - 忘记它们之间的任何交易。协议 (HTTP) 不是为此而构建的。
我见过的唯一事务性的是带有 WS-RM 扩展的 SOAP(带有可靠消息传递的 SOAP)。但是它的设置不是很容易(阅读:当你不这样做时让它工作可能是一场噩梦不知道你在做什么)而且并不是所有的 WS 框架都支持它。
当您确实需要在 Web 服务之间进行可靠的交付时,有一种方法。通常用于实现可靠交付的是具有存储转发模式的幂等服务 (https://en.m.wikipedia.org/wiki/Idempotence) 的消息传递。简单来说 - 服务 1 将 JMS 消息存储到队列中,并且有一个调用服务 2 的处理器 (MDB)。(是的,调用远程 Web 服务时,服务 2 可能会多次接收消息。幂等性是如何处理它。)
干杯
How to do Distributed Transactions XA ?
如果您首先调用 REST 或 Web 服务,然后再调用另一个,则这两个操作都不会成为事务的一部分。要形成交易,这些操作必须 "start" 交易或 "joined" 现有交易。要执行该事务,您的程序必须与事务监视器 (TM) 交互,例如 AT&T/Oracle Tuxedo (released in the 80s), the X/Open XA standard (released in the 90s) and the JTA-based systems.
所提议的注意基于 TM 的交易是如何工作的:
使用 XA 数据源的事务 基本上是一个在两个不同数据库上调用数据库操作的程序。同一个程序(例如,调用一个或多个 bean 中的方法)启动事务,对一个数据库执行某些操作,然后对另一个数据库执行其他操作。如果其中一个操作失败,则其他操作不执行或回滚。
使用 XA 数据源和支持 JTA 的组件的事务 基本上是一个将对一个或多个数据库的操作与其他支持事务的操作相结合的程序。例如,您可以将对数据库的操作与对内容存储库或基于网络的文件系统的操作结合起来。您可以定义在数据库操作失败时不执行或回滚文件系统操作的事务。通过在事务监视器中定义操作和补偿,可以将非事务应用程序(例如基于 COBOL 的程序)集成到事务中。
集成网络服务的事务需要特殊处理。例如,有 a proposal for webservice transactions 等 WS-Transaction 和 WS-Coordination 规范。有一个 coordinator 像事务监视器一样工作。软件必须调用协调器来启动事务。事务中的每个参与者都会报告每个操作是成功还是失败。协调器根据结果调用其他操作或调用补偿。
如今,有一些不依赖基于 TM 交易的软件架构建议。基于 CQRS and Event Sourcing implement transactions using the Sagas design pattern 的设计。如果您有兴趣定义调用两个 REST 服务的类似事务的操作,您可以考虑避免 XA/JTA 并编写一个 Sagas。
How to do Distributed Transactions XA in Spring and GlassFish 5?
你可以在网上查很多教程。例如,
- a tutorial 向您展示了三个用例:一个更新两个数据库,一个组合数据库操作和传出 JMS 消息,另一个组合传入 JMS 消息和数据库操作。
- a video 描述如何在 Spring 中使用 JTA 管理分布式事务
- 和来自 Spring 框架的 documentation。
If the two services work without errors, there is not problem. However, when the service
1
falls, the service2
does not know about the error and does not do the rollback.
这是正确的行为。当您调用 REST/webservice 时,由 REST/webservice 执行的操作不会加入事务。如果调用服务失败,被调用服务不会注意到它,也不会回滚它们在数据库中的操作。
I do not know if I need to configure another feature/option in GlassFish 5, or in the Spring program.
没有。您只需配置 XA 数据源。 Spring 将使用您的配置 class 和注释自动将您的应用程序对这些数据源执行的操作加入到事务中。例如,如果您有一个调用多个方法的 bean,这些方法对一个或多个 XA 数据源执行操作,这些操作将加入一个事务。
但是,当您在另一个应用程序中调用 REST/webservice 中的方法时,该 REST/webservice 执行的数据库操作将不会加入事务。