# Jakarta Transactions en Quarkus: Manejo de Transacciones Declarativas

## **Introducción**

Jakarta Transactions proporciona un mecanismo para manejar transacciones de base de datos de forma declarativa y programática. En Quarkus, las transacciones están completamente integradas y funcionan automáticamente con JPA.

## **¿Qué son las Transacciones?**

Una transacción es una secuencia de operaciones de base de datos que se ejecutan como una unidad atómica. Las transacciones garantizan las propiedades ACID:

* **Atomicity**: Todas las operaciones se completan o ninguna
    
* **Consistency**: La base de datos permanece en un estado válido
    
* **Isolation**: Las transacciones concurrentes no interfieren
    
* **Durability**: Los cambios persisten después del commit
    

## **Transacción Básica**

La forma más simple de usar transacciones en Quarkus es con `@Transactional`:

```go
@Transactional
public Hero createHero(String name, String power, Integer powerLevel) {
    Hero hero = new Hero(name, power, powerLevel);
    entityManager.persist(hero);
    entityManager.flush();
    return hero;
}
```

## **Tipos de Transacciones**

### **REQUIRED (por defecto)**

```go
@Transactional(Transactional.TxType.REQUIRED)
public Hero createHero(String name, String power, Integer powerLevel) {
    // Usa transacción existente si existe, sino crea una nueva
    Hero hero = new Hero(name, power, powerLevel);
    entityManager.persist(hero);
    return hero;
}
```

### **REQUIRES\_NEW**

```go
@Transactional(Transactional.TxType.REQUIRES_NEW)
public void logOperation(String message) {
    // Siempre crea una nueva transacción
    // Útil para operaciones que deben ejecutarse independientemente
    logger.info("Logging: " + message);
}
```

### **MANDATORY**

```go
@Transactional(Transactional.TxType.MANDATORY)
public void updateHeroPower(Long heroId, Integer newPowerLevel) {
    // Requiere que exista una transacción activa
    // Lanza excepción si no hay transacción
    Hero hero = entityManager.find(Hero.class, heroId);
    hero.setPowerLevel(newPowerLevel);
}
```

### **SUPPORTS**

```go
@Transactional(Transactional.TxType.SUPPORTS)
public Hero findHero(Long id) {
    // Usa transacción si existe, sino ejecuta sin transacción
    return entityManager.find(Hero.class, id);
}
```

### **NOT\_SUPPORTED**

```go
@Transactional(Transactional.TxType.NOT_SUPPORTED)
public String readOnlyOperation(Long heroId) {
    // Suspende cualquier transacción existente
    // Ejecuta sin transacción
    Hero hero = entityManager.find(Hero.class, heroId);
    return hero.getName();
}
```

### **NEVER**

```go
@Transactional(Transactional.TxType.NEVER)
public String nonTransactionalOperation(Long heroId) {
    // Lanza excepción si hay una transacción activa
    // Debe ejecutarse sin transacción
    Hero hero = entityManager.find(Hero.class, heroId);
    return hero.getName();
}
```

## **Rollback Automático**

Las transacciones hacen rollback automáticamente cuando se lanza una excepción no marcada:

```go
@Transactional
public PowerTransfer transferPower(Long fromHeroId, Long toHeroId, Integer amount) {
    Hero fromHero = entityManager.find(Hero.class, fromHeroId);
    Hero toHero = entityManager.find(Hero.class, toHeroId);
    
    // Crear registro
    PowerTransfer transfer = new PowerTransfer(fromHeroId, toHeroId, amount);
    entityManager.persist(transfer);
    
    // Actualizar niveles de poder
    fromHero.setPowerLevel(fromHero.getPowerLevel() - amount);
    toHero.setPowerLevel(toHero.getPowerLevel() + amount);
    
    // Si se lanza una excepción aquí, todas las operaciones se revierten
    throw new RuntimeException("Error - transaction will rollback");
}
```

## **Rollback Manual**

Puedes marcar una transacción para rollback manualmente:

```go
@Inject
TransactionManager transactionManager;

@Transactional
public void transferPowerWithManualRollback(Long fromHeroId, Long toHeroId, Integer amount) {
    try {
        // ... validaciones ...
        
        if (amount > 50) {
            // Marcar para rollback manual
            transactionManager.setRollbackOnly();
            throw new IllegalArgumentException("Amount too large");
        }
        
        // ... operaciones ...
    } catch (Exception e) {
        transactionManager.setRollbackOnly();
        throw e;
    }
}
```

## **Transacciones con Múltiples Operaciones**

Las transacciones garantizan que múltiples operaciones sean atómicas:

```go
@Transactional
public PowerTransfer transferPower(Long fromHeroId, Long toHeroId, Integer amount) {
    // 1. Validar héroes
    Hero fromHero = entityManager.find(Hero.class, fromHeroId);
    Hero toHero = entityManager.find(Hero.class, toHeroId);
    
    // 2. Crear registro de transferencia
    PowerTransfer transfer = new PowerTransfer(fromHeroId, toHeroId, amount);
    entityManager.persist(transfer);
    
    // 3. Actualizar niveles de poder (operaciones atómicas)
    fromHero.setPowerLevel(fromHero.getPowerLevel() - amount);
    toHero.setPowerLevel(toHero.getPowerLevel() + amount);
    
    entityManager.merge(fromHero);
    entityManager.merge(toHero);
    
    // Si cualquier operación falla, todas se revierten
    return transfer;
}
```

## **Timeout de Transacciones**

Puedes especificar un timeout para transacciones:

```go
@Transactional(timeout = 5) // 5 segundos
public void longRunningOperation() throws InterruptedException {
    // Si la operación excede 5 segundos, se cancela
    Thread.sleep(6000); // Excederá el timeout
}
```

## **Condiciones de Rollback Personalizadas**

Puedes especificar qué excepciones causan rollback:

```go
@Transactional(
    rollbackOn = {IllegalArgumentException.class, RuntimeException.class},
    dontRollbackOn = {IllegalStateException.class}
)
public void transferWithCustomRollback(Long fromHeroId, Long toHeroId, Integer amount) {
    if (fromHero == null) {
        // IllegalArgumentException causa rollback
        throw new IllegalArgumentException("Hero not found");
    }
    
    if (amount < 0) {
        // IllegalStateException NO causa rollback
        throw new IllegalStateException("Negative amount - no rollback");
    }
}
```

## **Transacciones Anidadas**

Las transacciones pueden anidarse usando REQUIRES\_NEW:

```go
@Transactional
public void nestedTransactionExample(Long heroId) {
    Hero hero = entityManager.find(Hero.class, heroId);
    
    // Esta llamada crea una nueva transacción independiente
    logOperation("Processing hero: " + hero.getName());
    
    // Si esta transacción hace rollback, el log anterior NO se revierte
    // porque se ejecutó en REQUIRES_NEW
}
```

## **Comparación de Tipos de Transacciones**

| **Tipo** | **Transacción Existente** | **Comportamiento** |
| --- | --- | --- |
| REQUIRED | Sí | Usa la existente |
| REQUIRED | No | Crea nueva |
| REQUIRES\_NEW | Sí | Suspende y crea nueva |
| REQUIRES\_NEW | No | Crea nueva |
| MANDATORY | Sí | Usa la existente |
| MANDATORY | No | Lanza excepción |
| SUPPORTS | Sí | Usa la existente |
| SUPPORTS | No | Sin transacción |
| NOT\_SUPPORTED | Sí | Suspende y ejecuta sin transacción |
| NOT\_SUPPORTED | No | Sin transacción |
| NEVER | Sí | Lanza excepción |
| NEVER | No | Sin transacción |

## **Ejemplo Completo**

Nuestro demo muestra:

* Transacciones básicas con @Transactional
    
* Todos los tipos de transacciones (REQUIRED, REQUIRES\_NEW, etc.)
    
* Rollback automático y manual
    
* Transacciones con múltiples operaciones atómicas
    
* Timeout de transacciones
    
* Condiciones de rollback personalizadas
    
* Transacciones anidadas
    

## **Ventajas en Quarkus**

1. **Declarativo**: @Transactional es suficiente para la mayoría de casos
    
2. **Integración Automática**: Funciona automáticamente con JPA
    
3. **Performance**: Transacciones eficientes
    
4. **Flexibilidad**: Múltiples tipos de transacciones según necesidad
    

## **Conclusión**

Las transacciones en Quarkus son simples de usar pero poderosas. El sistema declarativo con @Transactional hace que manejar transacciones sea fácil, mientras que los diferentes tipos proporcionan flexibilidad para casos complejos.

## **Recursos**

* [Demo completo](file:///Users/josediaz/Projects/JoeDayz/jakartaee-2026/quarkus-demos/transactions/)
    
* [Quarkus Transactions Guide](https://quarkus.io/guides/transaction)
    
* [Jakarta Transactions Specification](https://jakarta.ee/specifications/transactions/)
