事情就是在上周,我在Eclipse里写了一段查询语句,但是根据OpenJPA生成的SQL语句查询出来的数据,和预期的不一样。通过查看OpenJPA生成的SQL语句,终于发现OpenJPA在Or之前吞掉了我的括号。
现在,我们来还原一下现场,我最初的JPA查询语句是这样写的:
SELECT b FROM BorrowDocument b where b.borrowApprove.approveStatus= 'Approved' and (b.borrowApprove.borrowDocumentType = 'ElectronicBorrow' or (b.borrowApprove.borrowDocumentType = 'PaperBorrow' and b.bookStatus = 'Returned'))
OpenJPA生成的语句是这样的:
SELECT t0.PK_BORROWDOCUMENT_ID, t0.bookCount, t0.bookStatus,
t1.PK_BORROWAPPROVE_ID, t1.applyTime, t1.approveComments,
t1.approveStatus, t1.approveTime, t1.approverId, t1.approverName,
t1.borrowDocumentType, t1.borrowProcessType, t1.borrowPurpose,
t1.borrowType, t1.borrowerDept, t1.borrowerId, t1.borrowerName,
t1.processId, t1.returnDate, t0.borrowCopies, t0.docId, t0.docName,
t0.isFixed, t0.lendTime, t0.lentCount, t0.recordCode, t0.returnCount,
t0.returnTime, t0.securityLevel
FROM T_SYNM_BORROWDOCUMENT t0, T_SYNM_BORROWAPPROVE t1
WHERE (t1.approveStatus = ? AND (t1.borrowDocumentType = ? OR
t1.borrowDocumentType = ? AND t0.bookStatus = ?)) AND
t0.BORROWAPPROVEID = t1.PK_BORROWAPPROVE_ID AND ROWNUM <= ?
[params=?, ?, ?, ?, ?]
通过对比,可以发现OpenJPA在or (b.borrowApprove.borrowDocumentType = 'PaperBorrow' and b.bookStatus = 'Returned'))之后,生成SQL语句的过程中,Or后面的括号并没有被添加上。这是为什么呢?如果我们将Or后面的条件置前,是不是生成SQL语句还是没有括号。带着这个疑问,我将Or的条件置前了。
SQL查询语句是这样的:
SELECT b FROM BorrowDocument b where b.borrowApprove.approveStatus= 'Approved' and ((b.borrowApprove.borrowDocumentType = 'PaperBorrow' and b.bookStatus = 'Returned') or (b.borrowApprove.borrowDocumentType = 'ElectronicBorrow'))
OpenJPA生成的语句是这样的:
可以看出,这次OpenJPA仍然没有在生成SQL语句Or后面加上括号,但是这次的查询结果却是正确的。这是为什么呢?根据运算符的优先级顺序,or总是在And之后,OpenJPA为提高查询效率,在第一层总是尽可能的过滤掉更多的数据,如果将or提前查询,第一层过滤的数据就会减少,从而造成查询效率低下。OpenJPA自以为是的过滤掉了我所添加的括号,只不过现在是查询出来的数据完全是错误的数据了。
通过OpenJPA查询所出现的一个小问题,提醒我。不要只是把功能放在第一位,简单、高效的程序才是程序员应该追求的目标。