Viorel Viorel - 4 years ago 102
Java Question

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!

Answer Source

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 ";
Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download