0

I am trying to implement isolation level READ_UNCOMMITTED in a REST API in spring boot project. Following is the Controller and Service.

TicketCon.java

@RestController
@RequestMapping("/ticket/book/")
public class TicketCon {
    @Autowired
    private TicketSer ticketSer;
 
    @PostMapping("/1")
    public ResponseEntity<?> bookTicket1(@RequestBody TicketRequestDto ticketRequestDto) throws InterruptedException {
        ticketSer.bookTicket1(ticketRequestDto.getShowSeats());
        return ResponseEntity.ok("");
    }
 
    @PostMapping("/2")
    public ResponseEntity<?> bookTicket2(@RequestBody TicketRequestDto ticketRequestDto) throws InterruptedException {
        ticketSer.bookTicket2(ticketRequestDto.getShowSeats());
        return ResponseEntity.ok("");
    }
}

TicketSer.java

@Service
public class TicketSer {
    @Autowired
    private ShowSeatRepository showSeatRepository;
 
    @Transactional(isolation = Isolation.READ_UNCOMMITTED)
    public void bookTicket1(List<Long> showSeatsIds) throws InterruptedException {
        System.out.println("Reading Show Seats.");
        List<ShowSeat> showSeats = showSeatRepository.findAllByIdIn(showSeatsIds);
        showSeats.forEach(System.out::println);
 
        showSeats.forEach(s -> s.setShowSeatStatus(ShowSeatStatus.LOCKED));
        showSeatRepository.saveAll(showSeats);
        System.out.println("Show Seats LOCKED. Not Committed yet.");
        
        Thread.sleep(20000);
        System.out.println("Show Seats LOCKED. Will be Committed.");
    }
 
    @Transactional(isolation = Isolation.READ_UNCOMMITTED)
    public void bookTicket2(List<Long> showSeatsIds) throws InterruptedException {
        System.out.println("Reading Show Seats.");
        List<ShowSeat> showSeats = showSeatRepository.findAllByIdIn(showSeatsIds);
        showSeats.forEach(System.out::println);
    }
}

Initially, all the ShowSeat entities have ShowSeatStatus="AVAILABLE" in database.

First, I am executing ticket/book/1 API which will make ShowSeatStatus="LOCKED" for all the showSeatsIds passed and go to sleep state for 20 seconds without committing in database.

Then, after 5 seconds(before 1st transaction commits) I am executing ticket/book/2 API which is reading the same showSeatsIds passed.

I expect the output of 2nd API to print the ShowSeatStatus of passed showSeatIds as "LOCKED" because this is dirty read(uncommitted) data. But that's not happening. I am seeing output as "AVAILABLE" for those showSeatIds.

Where am I wrong here? Please help.

vipvipul1
  • 13
  • 3
  • DON'T use READ_UNCOMMITED. It doesn't solve any problems. If you have performance problems due to locking, fix them instead of trying to cover them up – Panagiotis Kanavos Aug 29 '23 at 16:13
  • `go to sleep state for 20 seconds without committing in database.` that's a bug in itself. Are you trying to use the database as a queue? Which database? It *matters* a lot. Using a table as a queue is complex and depends a *lot* on the database's locking model. Typically it involves *stricter* locking and *never* `READ_UNCOMMITTED` – Panagiotis Kanavos Aug 29 '23 at 16:16
  • You are using JPA, in-memory state will only be syncronized to the database while doing a commit (unless you explicitly flush). Next which database because not all database support all isolation levels. – M. Deinum Aug 29 '23 at 18:48
  • I am using MySql database. My actual requirement is to read uncommitted data on the ShowSeat entity being done by other transactions. – vipvipul1 Aug 29 '23 at 20:31

0 Answers0