oracle - GORM-使用订单和锁定选择最大记录-ORA-02014

标签 oracle hibernate grails gorm

如何使用GORM完成以下查询?

select * 
from T where id in 
(
    SELECT id
    FROM (
        SELECT *
        FROM T
        WHERE X is NULL
        ORDER BY Y DESC
        )
    WHERE ROWNUM <= 1
)
FOR UPDATE;

我正在尝试的方法调用如下所示:
T.findByXIsNull(sort: "Y", order:"desc", lock: true)

但是,出现以下错误(Oracle 11gR2):
ORA-02014:无法从具有DISTINCT,GROUP BY等的 View 中选择FOR UPDATE。

我认为它失败的原因是因为Hibernate将其转换为以下查询:
SELECT *
FROM (
    SELECT *
    FROM T
    WHERE X is NULL
    ORDER BY Y DESC
    )
WHERE ROWNUM <= 1 FOR UPDATE;

该查询试图将FOR UPDATE直接应用于限制rownum的子句。需要包装器选择语句来应用FOR UPDATE,如顶部的示例所示(此处讨论:How to solve ORA-02014: cannot select FOR UPDATE from view with DISTINCT, GROUP BY)。如何做到这一点?

更新1

当同时指定了order byrownnum <= ?时,这似乎是GORM / Hibernate中的一个错误,它会生成查询。以下两个都是单独工作的:
T.findByXIsNull(sort: "Y", order:"desc")
T.findByXIsNull(lock: true)

但是连同T.findByXIsNull(sort: "Y", order:"desc", lock:true)一起,它们将失败,并出现ORA-02014错误。修复方法是让Hibernate生成SQL,如我在本文顶部所述,该方法将锁包装到另一个外部select语句中。但是,可能有一个我不知道的解决方法。

最佳答案

AFAIK findBy*不支持分页和顺序参数,因为它将始终返回第一个匹配结果。

如果要使用排序,则必须使用findAllBy*,然后选择第一行进行锁定。

使用findBy我会尝试

//To avoid the infinitesimal chance of dirtiness between fetching and locking.
def t = T.findByXIsNull([lock: true])
//Round-about an unliked way 
def t = T.lock(T.findByXIsNull()?.id) 

//Or easier
def t = T.findByXIsNull()
t.lock()

findAllBy与分页参数一起使用:
def t = T.findAllByXIsNull(sort: "Y", order:"desc", max: 1, lock: true)

未经Oracle数据库测试

关于oracle - GORM-使用订单和锁定选择最大记录-ORA-02014,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17710030/

相关文章:

java - postgresql 的 Hibernate 5 命名策略

maven - 未检查存储库

java - Grails 中的 ImageTools 插件问题

oracle - 使用IP地址: The network adapter could not establish the connection访问Oracle数据库

java - 如何在实体类中添加 HashMap<Object, String>?

java - hibernate/ Spring 回滚插入没有错误

grails - grails如何创建单元测试

mysql - 'connect by' 或 'WITH RECURSIVE' 是否可以在高度连接的大数据场景中使用?

sql-server - Solaris 10 上的 Oracle ODBC 驱动程序

oracle - 在 apex 中创建一个包含两个详细信息的主详细信息页面