作为任何prod环境中的典型场景,我们有多个节点从数据库中获取和处理项目(oracle)。
我们希望确保每个节点从数据库中获取唯一的项集并对其进行操作。为了实现这一点,我们正在研究是否可以更新记录状态(例如,空闲到进程中),以及返回更新记录的相同更新查询。通过这种方式,每个节点都将在其自己的记录集上运行,而不会干扰彼此的集合。
由于维护原因,我们希望避免使用pl / sql。我们尝试使用“select for update”,但在少数情况下,它导致数据库锁定更长时间保持不变。
关于如何通过简单的sql或hibernate实现这一点的任何建议(因为我们也有hibernate选项可用)?
答案 0 :(得分:0)
对此有几点想法。首先在Oracle中,您可以使用RETURNING
子句作为更新语句的一部分,以将正在更新的表中的选择列(例如主键)返回到集合中。但是这个方法确实需要PL / SQL才能工作,因为你需要使用集合,尽管BULK事务可以减轻使用PL / SQL的一些缺点。
另一个选项是向表中添加一列,您可以在其中指明哪个节点正在处理记录,类似于您对状态列的指示,指示空闲或处理状态。如果没有被处理,这个将是NULL,或者是唯一标识在记录上工作的节点或进程的值。
在Stack上有一些额外的research导致this post使用带有Java的Oracles RETURNING INTO语句。关于Java支持的Oracles DML返回功能,它还可以直接返回Oracle自己的documentation
答案 1 :(得分:0)
最后,我们能够找到解决问题的方法。我们的问题陈述:在创建时间之前从列表顺序中声明前100个项目。因此,我们想要应用的逻辑基于FIFO
。因此,在这种情况下,每个节点将从数据库中获取前100个项目并开始对其进行处理。通过这种方式,每个节点将在其自己的一组项目上工作,而不会在每个其他路径上重叠。
我们通过在oracle数据库中创建TYPE
来实现此目的,然后使用hibernate声明项目并将声明的项目临时存储在TYPE
中。这是代码:
create type TMP_TYPE as table of VARCHAR2(1000);
// Hibernate代码
String query = "BEGIN UPDATE OUR_TABLE SET OUR_TABLE_STATUS = 'IP' WHERE OUR_TABLE_STATUS = 'ID' AND ID_OUR_TABLE IN (SELECT ID_OUR_TABLE FROM (SELECT ID_OUR_TABLE FROM OUR_TABLE ORDER BY AGEING_SINCE ASC ) ) AND ROWNUM < 101 RETURNING UUID BULK COLLECT INTO ?;END;";
Connection connection = getSession().connection();
CallableStatement cStmt = connection.prepareCall(query);
cStmt = connection.prepareCall(query);
cStmt.registerOutParameter(1, Types.ARRAY, " TMP_TYPE ");
cStmt.execute();
String[] updateBulkCollectArr = (String[]) (cStmt.getArray(1).getArray());
`
从这里了解Oracle Type and Bulk Collect 谢谢@Sentinel