복붙노트

[SPRING] 스프링 데이터 JPA로 엔티티를 찾을 때 LockModeType.PESSIMISTIC_WRITE를 활성화하는 방법은 무엇입니까?

SPRING

스프링 데이터 JPA로 엔티티를 찾을 때 LockModeType.PESSIMISTIC_WRITE를 활성화하는 방법은 무엇입니까?

이 코드와 동등한 효과를 얻으려면 어떻게해야합니까?

tx.begin();
Widget w = em.find(Widget.class, 1L, LockModeType.PESSIMISTIC_WRITE);
w.decrementBy(4);
em.flush();
tx.commit();

... Spring과 Spring-Data-JPA 주석을 사용하고 있습니까?

내 기존 코드의 기초는 다음과 같습니다.

@Service
@Transactional(readOnly = true)
public class WidgetServiceImpl implements WidgetService
{
  /** The spring-data widget repository which extends CrudRepository<Widget, Long>. */
  @Autowired
  private WidgetRepository repo;

  @Transactional(readOnly = false)
  public void updateWidgetStock(Long id, int count)
  {
    Widget w = this.repo.findOne(id);
    w.decrementBy(4);
    this.repo.save(w);
  }
}

그러나 updateWidgetStock 메소드의 모든 것이 비관적 인 잠금 세트로 수행되도록 지정하는 방법을 모르겠습니다.

LockModeType을 설정할 수있는 Spring Data JPA 어노테이션 인 org.springframework.data.jpa.repository.Lock이 있지만 updateWidgetStock 메소드에 넣을 수 있는지는 알 수 없습니다. Javadoc이 말하기를 WidgetRepository의 주석과 비슷하게 들립니다.

... 그래서 도움이되지 않는 것 같습니다.

lockModeType.PESSIMISTIC_WRITE가 설정된 상태에서 updateWidgetStock () 메서드를 실행하려면 어떻게해야합니까?

해결법

  1. ==============================

    1.@Lock은 Spring Data JPA의 1.6 버전에서 CRUD 메소드에서 지원됩니다 (실제로 이미 마일스톤이 있습니다). 자세한 내용은이 티켓을 참조하십시오.

    @Lock은 Spring Data JPA의 1.6 버전에서 CRUD 메소드에서 지원됩니다 (실제로 이미 마일스톤이 있습니다). 자세한 내용은이 티켓을 참조하십시오.

    이 버전을 사용하면 다음과 같이 간단하게 선언 할 수 있습니다.

    interface WidgetRepository extends Repository<Widget, Long> {
    
      @Lock(LockModeType.PESSIMISTIC_WRITE)
      Widget findOne(Long id);
    }
    

    이것은 CRUD 구현 부분에서 Backing 저장소 프록시가 EntityManager의 find (...) 호출에 구성된 LockModeType을 적용하게합니다.

  2. ==============================

    2.표준 findOne () 메소드를 오버라이드하고 싶지 않은 경우, select ...를 사용하여 다음과 같이 update 메소드를 사용하여 사용자 정의 메소드에서 잠금을 획득 할 수 있습니다.

    표준 findOne () 메소드를 오버라이드하고 싶지 않은 경우, select ...를 사용하여 다음과 같이 update 메소드를 사용하여 사용자 정의 메소드에서 잠금을 획득 할 수 있습니다.

    /**
     * Repository for Wallet.
     */
    public interface WalletRepository extends CrudRepository<Wallet, Long>, JpaSpecificationExecutor<Wallet> {
    
        @Lock(LockModeType.PESSIMISTIC_WRITE)
        @Query("select w from Wallet w where w.id = :id")
        Wallet findOneForUpdate(@Param("id") Long id);
    }
    

    그러나 PostgreSQL을 사용하는 경우 교착 상태를 방지하기 위해 잠금 시간 제한을 설정하려는 경우 상황이 다소 복잡해질 수 있습니다. PostgreSQL은 JPA 프로퍼티 또는 @QueryHint 주석으로 설정된 표준 프로퍼티 javax.persistence.lock.timeout을 무시합니다.

    내가 작동하도록 할 수있는 유일한 방법은 사용자 저장소를 생성하고 엔티티를 잠그기 전에 수동으로 시간 초과를 설정하는 것이 었습니다. 그것은 좋지는 않지만 적어도 작동합니다.

    public class WalletRepositoryImpl implements WalletRepositoryCustom {
    
    @PersistenceContext
    private EntityManager em;
    
    
    @Override
    public Wallet findOneForUpdate(Long id) {
        // explicitly set lock timeout (necessary in PostgreSQL)
        em.createNativeQuery("set local lock_timeout to '2s';").executeUpdate();
    
        Wallet wallet = em.find(Wallet.class, id);
    
        if (wallet != null) {
            em.lock(wallet, LockModeType.PESSIMISTIC_WRITE);
        }
    
        return wallet;
    }
    

    }

  3. ==============================

    3.이 답변을 무시하고 올리버 (Oliver)의 대답을 참조하는 것보다 스프링 데이터 1.6 이상을 사용할 수 있다면.

    이 답변을 무시하고 올리버 (Oliver)의 대답을 참조하는 것보다 스프링 데이터 1.6 이상을 사용할 수 있다면.

    스프링 데이터 비관적 인 @Lock 주석은 (지적한대로) 쿼리에만 적용됩니다. 내가 아는 주석은 전체 트랜잭션에 영향을 줄 수 있습니다. 비관적 인 잠금으로 findByOne을 호출하는 findByOnePessimistic 메소드를 만들거나 항상 비관적 인 잠금을 얻기 위해 findByOne을 변경할 수 있습니다.

    자신 만의 솔루션을 구현하고 싶다면 아마도 가능할 것입니다. 후드에서 @Lock 주석은 다음을 수행하는 LockModePopulatingMethodIntercceptor에 의해 처리됩니다.

    TransactionSynchronizationManager.bindResource(method, lockMode == null ? NULL : lockMode);
    

    ThreadLocal 멤버 변수가있는 정적 잠금 관리자를 만든 다음 ThreadLocal에 설정된 잠금 모드로 bindResource를 호출 한 모든 저장소의 모든 메서드를 래핑하는 애스펙트를 가질 수 있습니다. 이렇게하면 스레드 단위로 잠금 모드를 설정할 수 있습니다. 그런 다음 메서드를 실행하기 전에 스레드 별 잠금 모드를 설정하고 메서드를 실행 한 후이를 지우는 aspect에서 메서드를 래핑하는 @MethodLockMode 주석을 직접 만들 수 있습니다.

  4. from https://stackoverflow.com/questions/16159396/how-to-enable-lockmodetype-pessimistic-write-when-looking-up-entities-with-sprin by cc-by-sa and MIT license