• 카테고리

    질문 & 답변
  • 세부 분야

    백엔드

  • 해결 여부

    미해결

순수 Repository에도 락을 걸 수 있을까요?

22.02.04 10:11 작성 조회수 160

0

안녕하세요.
항상 좋은 강의와 답변 주셔서 감사합니다.
 
강의를 다 듣지 못해서 ㅠㅠ... 죄송하지만..
여기에 글을 적게 되었습니다.
 
제가 JPA의 DB쪽 동시성 병렬성 문제를 고민하던 중... @Lcok이라는 기능을 통해 DB쪽 문제까지 해결할 수 있다는 것을 알게 되어서... @LOCK을 순수 Repository나 Service에 걸려고 했었습니다.
 
그런데 하다 보니 @Lock이 Spring Data JPA 패키지에 있더라구요. 그래서 구글링을 해보니 많은 분들께서 JPA Repository 구현체에다가 @Lock을 적용하시는 것 같았습니다.
 
혹시 Spring Data Jpa Repository의 구현체가 아닌 순수 JPA에서도 @Lock 어노테이션을 정상적으로 사용할 수 있을까요?
제가 비관적 락을 걸고, Version으로 관리하는 코드를 작성해서 돌려봤는데... 비관적 락이 아니라, default인 낙관적 락으로 계속 돌아가는 것 같습니다... 다른 분들이 자겅한 코드를 확인해보니, JPA Repository 구현체에서는 정상적으로 @Lock이 먹히는 거 같습니다...
 
혹시 바쁘시겠지만... 알려주시면 너무 감사드리겠습니다...!
 
 
엔티티 코드
@Entity
@Data
public class MyEntity {

@Id
@GeneratedValue
private Long id;

private Long num;

@Version
private Long version;
}
 
 
리포지토리 코드
@Repository
@RequiredArgsConstructor
public class MyRepository {

private final EntityManager em;

@Transactional
@Lock(value = LockModeType.PESSIMISTIC_FORCE_INCREMENT)
public MyEntity save(MyEntity entity) {
em.persist(entity);
return entity;
}

public MyEntity findById(Long entityId) {
return em.find(MyEntity.class, entityId);
}
}

 
서비스 코드
@Service
@RequiredArgsConstructor
public class MyService {

private final MyRepository myRepository;


@Transactional
public MyEntity save(MyEntity entity) {
entity.setNum(entity.getNum() + 1);
myRepository.save(entity);
return entity;
}

@Transactional
public MyEntity saveEntity(Long entityId) {
MyEntity entity = myRepository.findById(entityId);
entity.setNum(entity.getNum() + 1);
myRepository.save(entity);
return entity;
}

}
 
테스트 코드 --> 돌리는 도중 낙관적 락에 의한 예외 코드 발생하며 종료
@SpringBootTest
public class MyEntityTest {


private static final ExecutorService service =
Executors.newFixedThreadPool(3);

@Autowired
private MyRepository myRepository;

@Autowired
private MyService myService;

private long accountId;
private Long entityId;

@BeforeEach
public void setUp() {

MyEntity myEntity = new MyEntity();
myEntity.setNum(10L);
myService.save(myEntity);
entityId = myEntity.getId();

}

@Test
public void raceCond() throws InterruptedException {
CountDownLatch latch = new CountDownLatch(3);
for (int i = 0; i < 3; i++) {
service.execute(() -> {
myService.saveEntity(entityId);
latch.countDown();
});
}
latch.await();


System.out.println("myRepository.findById(entityId) = " + myRepository.findById(entityId));
}
 
 
 
 
 
 
 
 
항상 좋은 강의와 답변 감사드립니다.
 

답변 1

답변을 작성해보세요.

0

안녕하세요. 안상혁님^^

JPA 책 16.1 트랜잭션과 락 부분을 참고해주세요.

감사합니다