30 Ağustos 2021 Pazartesi

SpringData JPA @Lock Anotasyonu - SELECT FOR UPDATE vs İçindir

Giriş
Şu satırı dahil ederiz
import org.springframework.data.jpa.repository.Lock;
Açıklaması şöyle
When using Spring Data, we can use the @Lock annotation in Spring repository methods to specify the desired lock mode.
LockModeType  olarak 
1. PESSIMISTIC_READ, 
2. PESSIMISTIC_WRITE, 
3. PESSIMISTIC_FORCE_INCREMENT
4. OPTIMISTIC_FORCE_INCREMENT 
kullanılabilir

Aslında altta şöyle bir şeye denk geliyor.
entityManager.lock(employee, LockModeType.PESSIMISTIC_WRITE);
Timeout 
Açıklaması şöyle
To lock entities pessimistically, set the lock mode to PESSIMISTIC_READ, PESSIMISTIC_WRITE, or PESSIMISTIC_FORCE_INCREMENT.

If a pessimistic lock cannot be obtained, but the locking failure doesn’t result in a transaction rollback, a LockTimeoutException is thrown.

Pessimistic Locking Timeouts

The length of time in milliseconds the persistence provider should wait to obtain a lock on the database tables may be specified using the javax.persistence.lock.timeout property. If the time it takes to obtain a lock exceeds the value of this property, a LockTimeoutException will be thrown, but the current transaction will not be marked for rollback. If this property is set to 0, the persistence provider should throw a LockTimeoutException if it cannot immediately obtain a lock.

If javax.persistence.lock.timeout is set in multiple places, the value will be determined in the following order:

1. The argument to one of the EntityManager or Query methods.
2. The setting in the @NamedQuery annotation.
3. The argument to the Persistence.createEntityManagerFactory method.
4. The value in the persistence.xml deployment descriptor.
LockModeType = PESSIMISTIC_READ
Sanırım şöyle bir SQL üretiyor
SELECT * FROM t WHERE i = 1 FOR SHARE;
LockModeType = PESSIMISTIC_WRITE
Örnek
Şöyle bir SQL üretiyor.
'select id from table where id = ? for update wait 5'
Şöyle yaparız.
interface WidgetRepository extends Repository<Widget, Long> {

  @Lock(LockModeType.PESSIMISTIC_WRITE)
  Widget findOne(Long id);
}
LockModeType = OPTIMISTIC_FORCE_INCREMENT 
Örnek
Elimizde şöyle bir kod olsun
@Entity
public class Product {

   @Id
   private Long id;

   private String name;

   private int quantity;

   @Version
   private Long version;

   // Getters and setters
}

@Repository
public interface ProductRepository extends 
  JpaRepository<Product, Long> {

   @Lock(LockModeType.OPTIMISTIC_FORCE_INCREMENT)
   Optional<Product> findById(Long id);

}
Kaydederken saveAll() için şöyle yaparız. Böylece bir sürü satır tek bir SQL cümlesi ile kaydedilir.
spring.jpa.properties.hibernate.jdbc.batch_versioned_data=true
Kullanmak için şöyle yaparız createProduct() işleminde flush() çağrılıyor. Böylece aynı versiyon numarasına sahip iki tane istek gelse bile flush() sayesinde hata varsa hemen görebiliriz
@Service
public class ProductService {
    
  @Autowired
  private ProductRepository productRepository;

  @Transactional
  public void updateProducts(List<Product> products) {
    productRepository.saveAll(products);
  }

  @Transactional
  public void createProduct(Product product) {
    productRepository.save(product);
    productRepository.flush(); // commit the transaction
  }
}


Hiç yorum yok:

Yorum Gönder