La integración de Seata en su modo AT para gestionar transacciones distribuidas, utilizando Nacos como centro de registro y configuración, es una estrategia robusta para aplicaciones Spring Boot. Esta guía proporciona una configuración completa y práctica, optimizada para entornos modernos (Spring Boot 3.x, Spring Cloud Alibaba 2023.x, Seata 2.0.0+, Nacos 2.x).
Arquitectura General
- TC (Transaction Coordinator): El servidor de Seata, encargado de orquestar las transacciones globales.
- TM (Transaction Manager): El servicio que inicia la transacción global (e.g., servicio de pedidos), marcado con la anotación
@GlobalTransactional. - RM (Resource Manager): Los servicios que participan en las ramas de la transacción (e.g., serviicos de inventario, pagos), los cuales se registran automáticamente en el TC.
- Nacos: Actúa simultáneamente como servicio de registro y centro de configuración.
- Modo AT: Emplea un proxy de base de datos (
DataSourceProxy) para generar automáticamente registros de reversión (undo_log) y facilitar la anulación de transacciones.
Requisitos Previos y Versiones Recomendadas
| Componente | Versión Sugerida |
|---|---|
| JDK | 17 |
| Maven | 3.8+ |
| MySQL | 8.0 |
| Nacos | 2.2.x ~ 2.3.x |
| Seata Server | 2.0.0 |
| Spring Boot | 3.2.x |
| Spring Cloud Alibaba | 2023.0.1.0 |
Nota importante: A partir de Seata 2.0.0, se recomienda configurar Seata mediante application.yml, eliminando la dependencia de archivos como registry.conf y file.conf.
Despliegue del Servidor Seata (TC)
1. Descarga y Extracción del Servidor Seata
wget https://github.com/seata/seata/releases/download/v2.0.0/seata-server-2.0.0.tar.gz
tar -zxvf seata-server-2.0.0.tar.gz
2. Inicialización de la Base de Datos de Seata
Cree la base de datos seata en su servidor MySQL y ejecute los scripts SQL proporcionados:
-- Ubicación del script: seata/script/server/db/mysql.sql
CREATE DATABASE seata;
USE seata;
-- Ejecute el contenido de mysql.sql para crear las tablas: global_table, branch_table, lock_table
3. Configuración de seata/conf/application.yml
seata:
config:
type: nacos
nacos:
server-addr: 127.0.0.1:8848 # Dirección de Nacos
group: SEATA_GROUP
namespace: "" # O especifique su ID de Namespace
username: nacos
password: nacos
data-id: seataServer.properties # Nombre del archivo de configuración en Nacos
registry:
type: nacos
nacos:
application: seata-server
server-addr: 127.0.0.1:8848
group: SEATA_GROUP
namespace: ""
cluster: default
username: nacos
password: nacos
store:
mode: db
db:
datasource: druid
db-type: mysql
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://127.0.0.1:3306/seata?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai
user: root
password: your_mysql_password
4. Creación del Archivo seataServer.properties en Nacos
En el panel de Nacos, cree un nuevo archivo de configuración:
- Data ID:
seataServer.properties - Group:
SEATA_GROUP
Contenido de ejemplo:
store.mode=db
store.db.datasource=druid
store.db.dbType=mysql
store.db.driverClassName=com.mysql.cj.jdbc.Driver
store.db.url=jdbc:mysql://127.0.0.1:3306/seata?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai
store.db.user=root
store.db.password=your_mysql_password
5. Inicio del Servidor Seata
cd seata/bin
./seata-server.sh -h 127.0.0.1 -p 8091 -m db
Tras el inicio, verifique en la consola de Nacos que el servicio seata-server se haya registrado correctamente.
Configuración de Microservicios Spring Boot (TM / RM)
A continuación, se muestra la configuración para el servicio de pedidos (order-service). Los servicios de inventario (stock-service) y pago (payment-service) se configuran de manera similar.
1. Dependencias Maven (pom.xml)
<dependencies>
<!-- Web Starter -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- Nacos Discovery -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
<version>2023.0.1.0</version>
</dependency>
<!-- Seata Starter -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-seata</artifactId>
<version>2023.0.1.0</version>
</dependency>
<!-- MySQL Connector & MyBatis -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>3.0.3</version>
</dependency>
</dependencies>
2. Configuración de application.yml
spring:
application:
name: order-service
cloud:
nacos:
discovery:
server-addr: 127.0.0.1:8848
username: nacos
password: nacos
seata:
enabled: true
application-id: ${spring.application.name}
tx-service-group: my_tx_group # IMPORTANTE: Debe coincidir con vgroup-mapping
data-source-proxy-mode: AT
enable-auto-data-source-proxy: false # Recomendado para un control manual más preciso
registry:
type: nacos
nacos:
server-addr: 127.0.0.1:8848
group: SEATA_GROUP
namespace: ""
username: nacos
password: nacos
config:
type: nacos
nacos:
server-addr: 127.0.0.1:8848
group: SEATA_GROUP
namespace: ""
username: nacos
password: nacos
data-id: seataServer.properties # Debe coincidir con el archivo de configuración del TC
service:
vgroup-mapping:
my_tx_group: default # Debe coincidir con tx-service-group
# grouplist: # A partir de Seata 2.0+, la resolución se hace vía Nacos, esta sección puede omitirse
# default: 127.0.0.1:8091
Establecer enable-auto-data-source-proxy: false permite la configuración manual del DataSourceProxy, crucial para evitar conflictos, especialmente con múltiples fuentes de datos.
3. Creación Manual del Proxy de DataSource (Paso Clave)
Es fundamental envolver su fuente de datos original con DataSourceProxy para que Seata pueda interceptar las operaciones SQL y generar los registros de reversión:
@Configuration
public class SeataDataSourceConfig {
@Bean
@ConfigurationProperties("spring.datasource") // Asegúrese de que coincida con su configuración de datasource
public DruidDataSource druidDataSource() {
return new DruidDataSource();
}
@Primary // Si tiene múltiples DataSources, marque el principal
@Bean("dataSource") // Nombre del bean
public DataSource dataSource(DruidDataSource druidDataSource) {
return new DataSourceProxy(druidDataSource);
}
}
4. Creación de la Tabla undo_log en Cada Base de Datos de Microservicio
Cada base de datos utilizada por los microservicios que participan en transacciones distribuidas debe contener la tabla undo_log:
-- Ejecutar en cada base de datos de negocio (e.g., order_db, stock_db, payment_db)
CREATE TABLE `undo_log` (
`id` BIGINT(20) NOT NULL AUTO_INCREMENT,
`branch_id` BIGINT(20) NOT NULL,
`xid` VARCHAR(100) NOT NULL,
`context` VARCHAR(128) NOT NULL,
`rollback_info` LONGBLOB NOT NULL,
`log_status` INT(11) NOT NULL,
`log_created` DATETIME NOT NULL,
`log_modified` DATETIME NOT NULL,
`ext` VARCHAR(100) DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `ux_undo_log` (`xid`, `branch_id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4;
Implementación del Código de Transacción Distribuida
TM (Lado del Iniciador - Servicio de Pedidos)
Utilice la anotación @GlobalTransactional para marcar los métodos que inician una transacción distribuida:
@RestController
public class OrderController {
@Autowired
private OrderService orderService;
@PostMapping("/createOrder")
@GlobalTransactional(name = "create-order-tx", rollbackFor = Exception.class)
public String createOrder(@RequestBody OrderDTO dto) {
// Llama a los servicios de stock y pago internamente
orderService.createOrder(dto);
return "success";
}
}
RM (Lado del Participante - Servicios de Stock/Pago)
Los servicios participantes solo necesitan usar la anotación estándar @Transactional de Spring. Seata interceptará estas transacciones automáticamente:
@Service
public class StockService {
@Transactional // Seata interceptará esta transacción
public void deductStock(Long productId, Integer count) {
// Lógica para deducir el inventario
stockMapper.updateStock(productId, count);
// Simulación de fallo: throw new RuntimeException("Stock insuficiente");
}
}
Verificación y Depuración
- Orden de Inicio:
- Inicie Nacos.
- Inicie el servidor Seata (TC).
- Inicie todos sus microservicios.
- Puntos de Verificación:
- Nacos Console: Verifique que
seata-servery todos los microservicios estén registrados. - Bases de Datos: Confirme la existencia de la tabla
undo_logen las bases de datos de negocio. - Logs: Revise los logs del cliente Seata para asegurar la conexión con el TC.
- Nacos Console: Verifique que
- Escenarios de Prueba:
- Flujo Normal: Ejecute una transacción completa y observe que todas las operaciones se confirmen.
- Flujo con Fallo: Simule un error en uno de los servicios (e.g., falta de stock) y observe que la transacción completa se revierta. Verifique que
undo_logse limpie correctamente.
Solución de Problemas Comunes
| Problema | Solución |
|---|---|
No available service 'default' |
Asegúrese de que tx-service-group en el cliente coincida exactamente con la clave en vgroup-mapping de la configuración de Seata. |
| Conexión fallida al Servidor Seata | Verifique que seata-server esté activo en Nacos y que el puerto 8091 (o el configurado) sea accesible. |
undo_log no se genera |
Confirme que está utilizando DataSourceProxy y que los métodos participantes tienen la anotación @Transactional. |
| Configuración de Seata 2.0.0 no se aplica | Asegúrese de haber eliminado las configuraciones de registry.conf y file.conf, y de que toda la configuración se realice a través de application.yml y Nacos. |
Al seguir estos pasos, habrá integrado exitosamente Seata AT con Nacos en sus proyectos Spring Boot, logrando consistencia transaccional distribuida. Los puntos clave a recordar son:
- Configurar el registro y la configuración del Servidor Seata a través de Nacos.
- Proxy manual de
DataSourceen los clientes. - Crear la tabla
undo_logen cada base de datos de negocio. - Usar
@GlobalTransactionalen el TM y@Transactionalestándar en los RM.
Para arquitecturas más complejas, considere la configuración de alta disponibilidad para el TC y el uso de múltiples namespaces en Nacos.