I've got the following case:
- Start transaction
- Fetch object A
- Update A
- Commit transaction
- Perform a long task with A
- Update A (not necessary within transaction, but it would be nice)
How to accomplish that? I do not want to have locked table during step 5. Steps 1-4 are expected to behave like "SELECT FOR UPDATE". Below is my current code. The method I'm executing is execute(). I'm testing it by executing it from different application instances and I'm checking, if instance A is able to do operations on table while instance B is executing executeJob(job).
@Service
@Slf4j
@Transactional
public class JobExecutionService {
private final Environment environment;
private final TestJobRepository testJobRepository;
private final TestJobResultRepository testJobResultRepository;
@Autowired
public JobExecutionService(Environment environment, TestJobRepository testJobRepository, TestJobResultRepository testJobResultRepository) {
this.environment = environment;
this.testJobRepository = testJobRepository;
this.testJobResultRepository = testJobResultRepository;
}
public void execute() {
TestJob job = getJob();
executeJob(job);
finishJob(job);
}
@Transactional
public TestJob getJob() {
TestJob testJob = testJobRepository.findFirstByStatusOrderByIdAsc(
0
);
testJob.setStatus(1);
testJobRepository.save(testJob);
return testJob;
}
public void executeJob(TestJob testJob) {
log.debug("Execution-0: {}", testJob.toString());
Random random = new Random();
try {
Thread.sleep(random.nextInt(3000) + 1000);
} catch (InterruptedException e) {
log.error("Error", e);
}
log.debug("Execution-1: {}", testJob.toString());
}
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void finishJob(TestJob testJob) {
testJobResultRepository.save(
new TestJobResult(
null,
testJob.getId(),
environment.getProperty("local.server.port")
)
);
}
}
public interface TestJobRepository extends PagingAndSortingRepository<TestJob, Long>, QueryDslPredicateExecutor<TestJob> {
@Lock(LockModeType.PESSIMISTIC_WRITE)
TestJob findFirstByStatusOrderByIdAsc(Integer status);
}