Я нашел параллельную проблему в своем приложении, где есть два потока, которые пытаются выполнить операцию записи в одно и то же время на одном узле или в Neo4J v2.2.5.Механизм блокировки на Neo4J
мне удалось воспроизвести проблему, используя простой способ:
базы данных Загрузка и импорт пример Neo4j фильм: http://example-data.neo4j.org/files/cineasts_12k_movies_50k_actors_2.1.6.zip Поскольку база данных устарела, так что вы должны добавить
allow_store_upgrade=true
вconf/neo4j.properties
для того, чтобы обновить авто базы данных ,Запустить Neo4j и запустить этот запрос на neo4jshell:
match (a:Actor {name: "Claude Jade"}), (m:Movie) merge (a)-[:ACTS_IN]->(m);
Это создаст ACTS_IN отношения с Актера "Claude Jade" ко всем узлам Movie. Причина этого заключается в том, чтобы сделать удаление узла «Claude Jade» актера (см. № 4 ниже) более продолжительным, поэтому вероятность одновременной проблемы больше.
Скачайте программу командной строки curl, если у вас ее еще нет. Мы будем использовать curl для отправки запроса в neo4j.
Создай файл Баш скрипт (имя файла до вас) с содержанием:
#!/bin/bash curl -XPOST http://localhost:7474/db/data/transaction/commit -H "Content-Type: application/json" -d '{"statements" : [ {"statement" : "MATCH (n:Actor {name: \"Claude Jade\"}) OPTIONAL MATCH (n)-[r]-() DELETE n, r"} ]}' & curl -XPOST http://localhost:7474/db/data/transaction/commit -H "Content-Type: application/json" -d '{"statements" : [ {"statement" : "MATCH (n:Actor {name: \"Claude Jade\"}) CREATE (n)-[:ACTS_IN]->(m:Movie {title: \"Hello World\"}) RETURN m"} ]}' & wait
Это будет работать два завиток процесса параллельно, где первый процесс попытается удалить «Claude Jade» Актер и все его отношения, а второй процесс попытается создать новое отношение ACTS_IN к актеру «Клод Джейд».
Запустите файл сценария в bash, например.
$ ./test.sh
Вот результат я получил:
{
"results" : [{
"columns" : ["m"],
"data" : [{
"row" : [{
"title" : "Hello World"
}
]
}
]
}
],
"errors" : []
} {
"results" : [{
"columns" : [],
"data" : []
}
],
"errors" : [{
"code" : "Neo.DatabaseError.Transaction.CouldNotCommit",
"message" : "org.neo4j.kernel.api.exceptions.TransactionFailureException: Node record Node[3150,used=false,group=55,prop=-1,labels=Inline(0x0:[]),light] still has relationships",
"stackTrace" : "java.lang.RuntimeException: org.neo4j.kernel.api.exceptions.TransactionFailureException: Node record Node[3150,used=false,group=55,prop=-1,labels=Inline(0x0:[]),light] still has relationships\r\n\tat org.neo4j.server.rest.transactional.TransitionalTxManagementKernelTransaction.commit(TransitionalTxManagementKernelTransaction.java:87)\r\n\tat org.neo4j.server.rest.transactional.TransactionHandle.closeContextAndCollectErrors(TransactionHandle.java:278)\r\n\tat
...
Примечание: если вы не видите какую-либо ошибку транзакции, то вам придется снова реимпортировать базу данных фильмов и повторно запустить описанные выше действия ,
Так от того, что я видел, удаление не удалось, поскольку он пытался удалить узел Актер и его всех ACTS_IN отношений, он сделал запрос MATCH первым (MATCH (n:Actor {name: \"Claude Jade\"}) OPTIONAL MATCH (n)-[r]-()
), но прежде чем он выполнил DELETE n, r
, 2-й процесс удалось вставить новое отношение ACTS_IN к узлу Actor, поэтому причина не удалась, потому что когда он пытался выполнить DELETE, у Актера уже было добавлено новое отношение.
Интересно, существует ли механизм блокировки Neo4J, который можно использовать для предотвращения этой проблемы?
Привет, спасибо за ваше решение, я попробовал, иногда это работает, но иногда я получил сообщение об ошибке для 2-го процесса завитка (создать новые отношения ACTS_IN): '{«результат» : [], "errors": [{"code": "Neo.ClientError.Statement.EntityNotFound", "message": "Невозможно загрузить NODE с идентификатором 3150."}]}' – jordom
С использованием фальшивого свойства вы фактически сериализуете два оператора, так как другим придется дождаться, когда первый будет зафиксирован. Поскольку вы запускаете оба оператора одновременно, не детерминировано, какое из те, кто первым захватывает блокировку.Если оператор удаления выбирает первый, он удалит узел и rels, а совпадение второго не будет выполнено (поскольку узел ушел) –
Если оператор удаления запускается первым, процесс 2-го совпадения действительно завершится неудачно , но он не должен возвращать ошибку, вместо этого он должен возвращать пустые данные. Я думаю, что произошло, когда строка 'SET n._fake = 1' была встречена во втором процессе, она остановила выполнение запроса до тех пор, пока 1-й процесс не выпустил Затем, когда он отпущен, он попытался возобновить выполнение запроса до следующей строки: 'CREATE (n) - [: ACTS_IN] -> (m: Movie {title: \" Hello World \ "}), однако узел 'n' уже удален 1-м процессом, поэтому ошибка« Невозможно загрузить NODE w с идентификатором ... ". – jordom