10 Kasım 2026 Salı

Transaction Isolation Level - Serializable

Örnek
Şöyle yaparız
BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE;
SELECT *
FROM doctors
WHERE status = 'ON_CALL';
Örnek
40001 hatası verir. Elimizde şöyle bir kod olsun.
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Transactional;

@Service
public class OrderService {
    @Transactional(isolation = Isolation.SERIALIZABLE)
    public OrderResult placeOrder(OrderRequest request) {
        // 1. Read current database state (e.g., check stock count)
        
        // 2. Validate business rules (e.g., is stock > 0?)
        
        // 3. Apply database modifications (e.g., deduct stock, save order)
        
        return new OrderResult("Success");
    }
}
Şöyle yaparız
import org.springframework.dao.PessimisticLockingFailureException;
import org.springframework.stereotype.Component;
import java.sql.SQLException;

@Component
public class TransactionRetryManager {
  private final OrderService orderService;
  public TransactionRetryManager(OrderService orderService) {
    this.orderService = orderService;
  }
  public OrderResult processWithRetry(OrderRequest request) {
    int maxAttempts = 3;
    for (int attempt = 1; attempt <= maxAttempts; attempt++) {
      try {
        // Try executing the transactional method
        return orderService.placeOrder(request);
      } catch (RuntimeException ex) {
        // Check if this exception was caused by Postgres SQLSTATE 40001
        if (!isSerializationFailure(ex)) {
          throw ex; // It's a different error (e.g., bad SQL syntax), give up immediately
        }
        // If we ran out of attempts, stop retrying and throw the error
        if (attempt == maxAttempts) {
          throw ex;
        }
                
        // Optional: Add a brief pause (backoff) here before trying again
       }
     }
     throw new IllegalStateException("Unexpected retry state reached");
  }

  private boolean isSerializationFailure(RuntimeException ex) {
    // Look down the exception chain to find the root JDBC SQLException
    Throwable cause = ex.getCause();
    while (cause != null) {
      if (cause instanceof SQLException sqlEx) {
        // Deterministically match the exact Postgres serialization error code
        if ("40001".equals(sqlEx.getSQLState())) {
          return true;
        }
      }
      cause = cause.getCause();
    }
    return false;
  }
}

Hiç yorum yok:

Yorum Gönder