In my Neo4j based application I have a classical find-or-create usecase: I ask neo4j if there is already a node with a special relationship to other nodes. If not, then I'll create one within the same transaction. Nothing special... But if I call this method multi-threaded (or n-clients connected to the same database), then, from time to time, I got an exception which says that there are more than one elements matching my query. That means there were two threads few moments before which both have created the same 'pair'-node. Synchronization at java-level is not an option (since requests can come from more than one client/server).
How can I solve such issues other than catching the exception and delete the duplicated node afterwards?
I use Spring Data Neo4j 2.3.3 and Neo4j 1.9.5.
Here is my query:
START expected=node({0}), actual=node({1}) MATCH (expected)<-[:EXPECTED]- (pair) -[:ACTUAL]->(actual) RETURN pair
Btw. The thrown exception in this case is a NoSuchElementException, at least for me this is a bit confusing.
WARN [00:32.31,962] de.xxx.web.AbstractExceptionHandlers: error.NoSuchElementException
java.util.NoSuchElementException: More than one element in org.neo4j.cypher.PipeExecutionResult$$anon$1@8f0dc23. First element is '{pair=Node[20001]}' and the second element is '{pair=Node[20000]}'
at org.neo4j.helpers.collection.IteratorUtil.singleOrNull(IteratorUtil.java:122)
at org.neo4j.helpers.collection.IteratorUtil.singleOrNull(IteratorUtil.java:289)
at org.springframework.data.neo4j.conversion.QueryResultBuilder$1.singleOrNull(QueryResultBuilder.java:94)
at org.springframework.data.neo4j.repository.query.GraphRepositoryQuery.dispatchQuery(GraphRepositoryQuery.java:108)
at org.springframework.data.neo4j.repository.query.GraphRepositoryQuery.execute(GraphRepositoryQuery.java:81)
at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.invoke(RepositoryFactorySupport.java:337)
at org.springframework.aop.framework.ReflectiveMethodvocation.proceed(ReflectiveMethodvocation.java:172)
at org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithvocation(TransactionInterceptor.java:96)
at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:260)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:94)
at org.springframework.aop.framework.ReflectiveMethodvocation.proceed(ReflectiveMethodvocation.java:172)
at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:155)
at org.springframework.aop.framework.ReflectiveMethodvocation.proceed(ReflectiveMethodvocation.java:172)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:204)
at com.sun.proxy.$Proxy63.findByAttributes(Unknown Source)
at de.xxx.core_service.attribute.AttributeManagerImpl.findOrCreatePair_aroundBody32(AttributeManagerImpl.java:212)
at de.xxx.core_service.attribute.AttributeManagerImpl$AjcClosure33.run(AttributeManagerImpl.java:1)