Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Spring JPA Locking Concept

Anybody have any idea how to use Locking with UPDATE statement in Spring JPA, so that only one thread can UPDATE the record at a time?

Here, I am trying to update the availability of table name aircraft_route and before updating, I want to take the lock of that row so that no other thread can update it at the same time.

Error: Illegal attempt to set lock mode on a native SQL query

Any help would be appreciated.

Thanks

AirCraftRoute.java

@Builder
@Setter
@Getter
@AllArgsConstructor
@NoArgsConstructor
@Entity(name = "aircraft_route")
public class AirCraftRoute implements Serializable
{
    @EmbeddedId
    private AirCraftRoutePK pk = new AirCraftRoutePK();

    @ManyToOne
    @MapsId("airCraftId")
    @JoinColumn(name = "aircraft_id")
    private AirCraft airCraft;

    @ManyToOne
    @MapsId("routeId")
    @JoinColumn(name = "route_id")
    private Route route;

    @Column(name = "journey_date")
    private Date journeyDate;

    @Column(name = "departure_time")
    private Time departureTime;

    @Column(name = "arrival_time")
    private Time arrivalTime;

    @Column(name = "fare")
    private float fare;

    @Column(name = "availability")
    private int availability;

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (!(o instanceof AirCraftRoute)) return false;
        AirCraftRoute that = (AirCraftRoute) o;
        return Float.compare(that.getFare(), getFare()) == 0 &&
                Objects.equals(getAirCraft(), that.getAirCraft()) &&
                Objects.equals(getRoute(), that.getRoute()) &&
                Objects.equals(getJourneyDate(), that.getJourneyDate()) &&
                Objects.equals(getDepartureTime(), that.getDepartureTime()) &&
                Objects.equals(getArrivalTime(), that.getArrivalTime());
    }

    @Override
    public int hashCode() {
        return Objects.hash(getAirCraft(), getRoute(), getJourneyDate(), getDepartureTime(), getArrivalTime(), getFare());
    }
}

AirCraftRouteRepository.java

@Repository
public interface AirCraftRouteRepository extends JpaRepository<AirCraftRoute,Integer> {

    @Transactional
    @Query(value = "SELECT ar.availability FROM aircraft_route ar WHERE ar.aircraft_id = :airCraftId AND ar.route_id = :routeId FOR UPDATE",nativeQuery = true)
    int getAvailability(@Param("airCraftId") Long airCraftId, @Param("routeId") Long routeId);

    @Modifying
    @Transactional
    @Lock(LockModeType.PESSIMISTIC_WRITE)
    @Query(value = "UPDATE aircraft_route ar SET ar.availability = ar.availability - :numberOfTickets WHERE ar.aircraft_id = :airCraftId AND ar.route_id = :routeId AND ar.availability > 0",nativeQuery = true)
    int updateAvailability(@Param("numberOfTickets") int numberOfTickets,@Param("airCraftId") Long airCraftId, @Param("routeId") Long routeId);
}
like image 855
Gibran Mohammad Khan Avatar asked Oct 31 '25 03:10

Gibran Mohammad Khan


1 Answers

I think you don't need the Lock at all for native SQL. You can FOR UPDATE directly in the native query. Like this

@Transactional
@Query(value = "SELECT * FROM aircraft_route ar WHERE ar.aircraft_id = :airCraftId AND ar.route_id = :routeId FOR UPDATE",nativeQuery = true)
List<Integer> getAvailability(@Param("airCraftId") Long airCraftId, @Param("routeId") Long routeId);
like image 182
StanislavL Avatar answered Nov 04 '25 09:11

StanislavL



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!