0

[Java Backend Zero to Hello] [Phase 4] BÀI 4.10: TRANSACTION & LOCKING

📚 Series: Java Backend Zero to Hello 📂 Phân đoạn: Phase 4: Database & SQL 📖 Nội dung: BÀI 4.10: TRANSACTION & LOCKING 💡 Khóa học lập trình Backend Java & Spring Boot chuẩn doanh nghiệp từ con số 0.


BÀI 4.10: TRANSACTION & LOCKING

Mục tiêu

  • Hiểu Transaction và ACID
  • Sử dụng @Transactional
  • Các Isolation Level
  • Optimistic và Pessimistic Locking

1. TRANSACTION LÀ GÌ?

Transaction là một đơn vị công việc logic, tuân thủ ACID:

  • Atomicity: Tất cả hoặc không có gì
  • Consistency: Dữ liệu luôn hợp lệ
  • Isolation: Các transaction độc lập
  • Durability: Commit thì không mất

2. @TRANSACTIONAL (SPRING)

2.1 Cơ bản

@Service
public class UserService {

    @Transactional
    public void createUser(User user) {
        userRepository.save(user);
        // Tự động commit nếu không có exception
        // Tự động rollback nếu có RuntimeException
    }
}

2.2 Các thuộc tính

@Transactional(
    propagation = Propagation.REQUIRED,    // Mặc định
    isolation = Isolation.DEFAULT,
    timeout = 30,                          // seconds
    readOnly = false,
    rollbackFor = Exception.class,         // Rollback cho cả checked
    noRollbackFor = RuntimeException.class // Không rollback
)

2.3 Propagation

Propagation Mô tả
REQUIRED Dùng transaction hiện có, hoặc tạo mới (mặc định)
REQUIRES_NEW Luôn tạo transaction mới
NESTED Nested transaction
SUPPORTS Dùng transaction nếu có
NOT_SUPPORTED Chạy không có transaction
MANDATORY Bắt buộc có transaction
NEVER Không được có transaction

2.4 Ví dụ

@Service
public class OrderService {

    @Transactional
    public void createOrder(Order order) {
        orderRepository.save(order);
        // Gọi method khác - cùng transaction
        paymentService.processPayment(order);
    }
}

@Service
public class PaymentService {

    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public void processPayment(Order order) {
        // Transaction riêng - commit độc lập
        paymentRepository.save(new Payment(order));
    }
}

3. ISOLATION LEVEL

3.1 Các vấn đề

Vấn đề Mô tả
Dirty Read Đọc dữ liệu chưa commit
Non-repeatable Read Đọc 2 lần khác giá trị
Phantom Read Số dòng thay đổi giữa 2 lần đọc

3.2 Các level

Level Dirty Read Non-repeatable Phantom
READ_UNCOMMITTED ✅ ✅ ✅
READ_COMMITTED ❌ ✅ ✅
REPEATABLE_READ ❌ ❌ ✅
SERIALIZABLE ❌ ❌ ❌

3.3 Cấu hình

@Transactional(isolation = Isolation.READ_COMMITTED)
public void processOrder() { ... }

4. LOCKING

4.1 Optimistic Locking

Giả định không có conflict, kiểm tra khi commit.

@Entity
public class Product {
    @Id
    @GeneratedValue
    private Long id;

    private String name;
    private int stock;

    @Version
    private Long version;  // Tự động tăng khi update
}
// Sử dụng
Product product = em.find(Product.class, 1L);
product.setStock(product.getStock() - 1);
em.merge(product);  // Ném OptimisticLockException nếu version không khớp

4.2 Pessimistic Locking

Khóa dòng ngay khi đọc.

@Lock(LockModeType.PESSIMISTIC_WRITE)
@Query("SELECT p FROM Product p WHERE p.id = :id")
Optional<Product> findByIdForUpdate(@Param("id") Long id);
@Transactional
public void decreaseStock(Long productId, int quantity) {
    Product product = productRepository.findByIdForUpdate(productId)
        .orElseThrow();
    product.setStock(product.getStock() - quantity);
    // Lock được giải phóng khi commit
}

4.3 So sánh

Optimistic Pessimistic
Không khóa khi đọc Khóa ngay khi đọc
Kiểm tra khi commit Chờ commit
Hiệu năng cao Hiệu năng thấp
Ít conflict Nhiều conflict
Dùng @Version Dùng SELECT FOR UPDATE

5. DEADLOCK

5.1 Ví dụ

Transaction A: Lock row 1, cần lock row 2
Transaction B: Lock row 2, cần lock row 1
→ Deadlock!

5.2 Cách tránh

  • Lock theo thứ tự nhất quán
  • Dùng timeout
  • Retry khi gặp deadlock
  • Tránh lock quá lâu
@Transactional
public void transfer(Long fromId, Long toId, double amount) {
    // Lock theo thứ tự ID tăng dần
    Long firstId = Math.min(fromId, toId);
    Long secondId = Math.max(fromId, toId);

    Account first = accountRepository.findByIdForUpdate(firstId);
    Account second = accountRepository.findByIdForUpdate(secondId);

    // ...
}

6. TRANSACTION TEMPLATE

@Service
public class UserService {

    @Autowired
    private TransactionTemplate transactionTemplate;

    public void createUser(User user) {
        transactionTemplate.execute(status -> {
            userRepository.save(user);
            return null;
        });
    }
}

7. BÀI TẬP THỰC HÀNH

Bài 1: Transfer Money

@Transactional(isolation = Isolation.READ_COMMITTED)
public void transfer(Long fromId, Long toId, double amount) {
    Account from = accountRepository.findByIdForUpdate(fromId)
        .orElseThrow(() -> new NotFoundException("From account"));
    Account to = accountRepository.findByIdForUpdate(toId)
        .orElseThrow(() -> new NotFoundException("To account"));

    if (from.getBalance() < amount) {
        throw new InsufficientFundsException();
    }

    from.setBalance(from.getBalance() - amount);
    to.setBalance(to.getBalance() + amount);
}

Bài 2: Optimistic Locking

Thêm @Version vào entity, test conflict.

Bài 3: Rollback Rules

Test rollback với các loại exception khác nhau.


8. TÓM TẮT

Khái niệm Mô tả
@Transactional Quản lý transaction
Propagation Cách lan truyền transaction
Isolation Mức độ cô lập
Optimistic Lock Dùng @Version
Pessimistic Lock SELECT FOR UPDATE
Deadlock Xung đột khóa

Hoàn thành Phase 4! Tiếp tục với Phase 5: Spring Framework & Spring Boot


🧭 Điều hướng bài học

⭐ Hãy bookmark (clip) lại series để tiện theo dõi các bài học tiếp theo nhé!


All rights reserved

Viblo
Hãy đăng ký một tài khoản Viblo để nhận được nhiều bài viết thú vị hơn.
Đăng kí