Java实现Neo4j存储过程删除节点与关系时的异常排查
问题描述
用Java编写Neo4j存储过程时,一个用于撤销节点和关系的过程出现异常,相关代码如下:
while (Objects.nonNull(espnStack) && !espnStack.isEmpty()) { Node thisTestedNode = espnStack.pop(); Stack<Node> stackOfBlockNodes = findEquityProperties.getAllBlockNodes(thisTestedNode); while (Objects.nonNull(stackOfBlockNodes) && !stackOfBlockNodes.isEmpty()) { Node thisBlockNode = stackOfBlockNodes.pop(); Iterable<Relationship> allRels = thisBlockNode.getRelationships(); for (Relationship thisRel : allRels) { thisRel.delete(); } thisBlockNode.delete(); } }
调试时代码能正常找到并删除节点和关系,但调用返回时抛出异常:
org.neo4j.driver.exceptions.ClientException: Node with id 2 has been deleted in this transaction
单元测试代码如下:
Record record = session.run ( "MATCH (p) WHERE p.name = 'USP'\n" + "MATCH (s) WHERE s.name = 'GSUB'\n" + "CALL myProcedure.delete_equity(p,s) YIELD returnedObjects\n" + "RETURN returnedObjects\n" ).single();
在Neo4j Desktop中运行该过程无报错但无任何效果,尝试手动调用Transaction.commit()时提示无法在过程内提交事务。
解决思路
1. 修复返回对象引发的异常
存储过程YIELD的returnedObjects如果包含已被删除的Node或Relationship实例,事务结束时会触发节点已删除的异常。修改过程逻辑,让YIELD返回删除统计数据(如删除的节点数、关系数),而非被删除的节点对象本身。
2. 避免重复删除节点
检查getAllBlockNodes方法是否会返回重复的节点实例,导致代码尝试删除同一个节点多次。可以在删除节点前增加判断:
if (!thisBlockNode.isDeleted()) { // 执行删除关系和节点的逻辑 }
3. 确保调用方正确管理事务
Neo4j存储过程的事务由调用客户端控制,过程内部不能手动提交:
- 单元测试中,若使用显式事务模式,需在执行查询后手动提交事务:
try (Transaction tx = session.beginTransaction()) { Record record = tx.run(...).single(); tx.commit(); } - 在Neo4j Desktop中执行查询时,确保单条查询完整执行,若涉及多步操作,需用
BEGIN和COMMIT包裹,确保在同一个事务中完成。
4. 优化节点删除逻辑
- 遍历关系时,将
Iterable<Relationship>转换为List后再删除,避免遍历过程中集合结构变化引发的问题:List<Relationship> rels = StreamSupport.stream(allRels.spliterator(), false) .collect(Collectors.toList()); for (Relationship thisRel : rels) { thisRel.delete(); } - 明确指定关系方向,确保所有关联关系都被删除:
Iterable<Relationship> allRels = thisBlockNode.getRelationships(Direction.BOTH);
内容的提问来源于stack exchange,提问作者Rasputin
相关产品推荐
相关产品推荐

