我的Neo4j服务器在执行并发请求时抛出DeadlockDetectedExceptions,我无法弄清楚原因。
以下代码由客户端REST请求调用的服务器插件调用,并在单个事务中发生。
Node nFollowing = loadUser(idFollowing);
Node nFollowed = loadUser(idFollowed);
// locking order to avoid deadlocks
if (Long.valueOf(idFollowing) < Long.valueOf(idFollowed)) {
tx.acquireWriteLock(nFollowing);
tx.acquireWriteLock(nFollowed);
} else {
tx.acquireWriteLock(nFollowed);
tx.acquireWriteLock(nFollowing);
}
// create relationship if not present
for (Relationship followship : nFollowing.getRelationships(
EdgeType.FOLLOWS, Direction.OUTGOING)) {
if (followship.getEndNode().equals(nFollowed)) {
return;
}
}
nFollowing.createRelationshipTo(nFollowed, EdgeType.FOLLOWS);
虽然我想到了死锁,但是抛出了以下异常,表明在创建关系时发生了死锁。
例外(略有减少):
"ForsetiClient[78] can't acquire ExclusiveLock{owner=ForsetiClient[73]} on
RELATIONSHIP(49), because holders of that lock are waiting for ForsetiClient[78].\n
Wait list:ExclusiveLock[ForsetiClient[73] waits for [73, 78, ]]",
"exception" : "DeadlockDetectedException",
"fullname" : "org.neo4j.kernel.DeadlockDetectedException",
"stacktrace" : [
"org.neo4j.kernel.ha.lock.forseti.ForsetiClient.markAsWaitingFor(ForsetiClient.java:611)",
"org.neo4j.kernel.ha.lock.forseti.ForsetiClient.acquireExclusive(ForsetiClient.java:190)",
"org.neo4j.kernel.impl.nioneo.xa.TransactionalRelationshipLocker.getWriteLock(TransactionalRelationshipLocker.java:33)",
"org.neo4j.kernel.impl.core.NodeProxy.createRelationshipTo(NodeProxy.java:455)",
"de.uniko.sebschlicht.neo4j.graphity.WriteOptimizedGraphity.addFollowship(WriteOptimizedGraphity.java:40)",
"de.uniko.sebschlicht.neo4j.graphity.Graphity.addFollowship(Graphity.java:115)",
"de.uniko.sebschlicht.neo4j.GraphityBaselinePlugin.follow(GraphityBaselinePlugin.java:38)",
"org.neo4j.server.rest.web.ExtensionService.invokeGraphDatabaseExtension(ExtensionService.java:134)",
"org.neo4j.server.rest.transactional.TransactionalRequestDispatcher.dispatch(TransactionalRequestDispatcher.java:139)"
]
我无法理解原因:我已经锁定了nFolloing
和nFollowed
。实际上,死锁不是针对节点锁定而是关系锁定。由于仅在尚未存在的情况下才创建关系,因此锁定持有者必须是当前关系。
如果这是对的,那么锁具持有人正在等待自己。 我怎样才能避免这种情况或者其他什么事情试图说出来?
以防万一:
我不想使用Neo4j suggested和marked as to be avoided的synchronized
块,因为它会大大减慢我的服务速度,我不希望这些并发请求经常发生。
答案 0 :(得分:1)
死锁是由snychronized
块和手动事务锁引起的。我错过了从我之前执行的测试中删除synchronized
语句。
虽然synchronized
语句没有以锁定节点为目标,但引发了异常。似乎这两种锁定机制是不兼容的。
这导致了一条奇怪的错误消息,对我来说不是很有帮助。