简体   繁体   中英

Using pessimistic lock in a JPA query when values could be null

Assuming I have a query with a condition and I need to have the results locked:

public List<E> findTableRows(String distributor, String status) {
  String queryStr = "SELECT l "
                  + "FROM   Carrier child "
                  + "LEFT   JOIN child.parentCarrier parent, "
                  + "       Label l "
                  + "WHERE  (child.distributor = :distributor or parent.distributor = :distributor) "
                  + "AND    (child.label = l or parent.label = l) "
                  + "AND    l.status = :status ";

  Query q = entityManager.createQuery(queryStr);

  q.setParameter("distributor", distributor);
  q.setParameter("status", status);
  q.setLockMode(LockModeType.PESSIMISTIC_FORCE_INCREMENT);

  return q.getResultList();
}

The parentCarrier can also be a Carrier , depending on how they get loaded on a truck, for example boxes (which have no parent if they get loaded directly) and boxes on pallets (for which the pallets would be the parent). Labels can belong either to a box if it has no parent or to the pallet on which they reside.

If I execute this query, there is a chance that the labels do not have the right status yet, which is fine, because we do not need to do anything with labels that don't match the criteria. However, if this happens, then I get this error:

FOR UPDATE cannot be applied to the nullable side of an outer join

I could try to count the labels beforehand and not execute this query if there are no results or first get a list of labels for the carriers of a distributor that we want to process, but would like to avoid executing 2 queries. Is there any other way to solve this.

Thanks!

The solution seems to be simply putting the table you need to select from first and then do all the other joins later, for the case mentioned in the issue, a query like this works:

String queryStr = "SELECT l "
                + "FROM   Label l, "
                + "       Carrier child "
                + "LEFT   JOIN child.parentCarrier parent "
                + "WHERE  (child.distributor = :distributor or parent.distributor = :distributor) "
                + "AND    (child.label = l or parent.label = l) "
                + "AND    l.status = :status ";

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM