JPA同時性の問題
25711 ワード
背景
コード#コード#
ろんり
DTO
@Getter
public static class CreateUpdate{
private String status;
}
Service
public TaskEntity findTask(Long id) {
Optional<TaskEntity> findTask = taskRepository.findById(id);
return findTask.orElse(null);
}
@Transactional
public TaskEntity updateTask(Long id, TaskDto.CreateUpdate createUpdate, int sleepTime){
TaskEntity taskEntity = findTask(id);
threadSleep(sleepTime);
taskEntity.updateStatus(createUpdate.getStatus());
taskEntity.updateTime(createUpdate.getStatus());
return taskEntity;
}
public void threadSleep(int sleepTime){
try {
Thread.sleep(sleepTime);
} catch (Exception e){
log.info(e.getMessage());
}
}
Repository
public interface TaskRepository extends JpaRepository<TaskEntity, Long>
Domain
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@Entity
public class TaskEntity {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String status;
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss", timezone = "Asia/Seoul")
private LocalDateTime startTime;
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss", timezone = "Asia/Seoul")
private LocalDateTime endTime;
private Long duration;
@Builder
public TaskEntity(String status){
this.status = status;
}
public void updateStatus(String status){
this.status = status;
}
public void updateTime(String status) {
if (this.startTime == null){
this.startTime = LocalDateTime.now().withNano(0);
}
if (status.equals("Succeeded")){
this.endTime = LocalDateTime.now().withNano(0);
this.duration = Duration.between(this.startTime,this.endTime).getSeconds();
}
}
}
Test
@Test
@DisplayName("Lock 적용하기 전")
void test1() throws Exception {
// given
TaskEntity newTask = TaskEntity.builder()
.status("Created")
.build();
taskService.createTask(newTask);
// when
final ExecutorService executor = Executors.newFixedThreadPool(3);
executor.execute(()->taskService.updateTask(newTask.getId(), TaskDto.CreateUpdate.builder().status("Started").build(), 2000));
Thread.sleep(500);
executor.execute(()->taskService.updateTask(newTask.getId(), TaskDto.CreateUpdate.builder().status("Running").build(), 1000));
Thread.sleep(500);
executor.execute(()->taskService.updateTask(newTask.getId(), TaskDto.CreateUpdate.builder().status("Succeeded").build(), 100));
// Thread 작업이 다 끝날때까지 최대 10초 대기
executor.shutdown();
executor.awaitTermination(10, TimeUnit.SECONDS);
//then
TaskEntity findTask = taskService.findTask(newTask.getId());
assertAll(
()-> assertEquals("Started", findTask.getStatus()),
()-> assertNotEquals(null,findTask.getStartTime()),
()-> assertEquals(null,findTask.getEndTime()),
()-> assertEquals(null,findTask.getDuration())
);
}
数式化
n/a.結論
Reference
この問題について(JPA同時性の問題), 我々は、より多くの情報をここで見つけました https://velog.io/@sgwon1996/JPA-동시성-문제テキストは自由に共有またはコピーできます。ただし、このドキュメントのURLは参考URLとして残しておいてください。
Collection and Share based on the CC Protocol