How to mark custom Spring Data Neo4j 5.0.3 cypher request as read-only

I am currently working on the Spring REST API Data Neo4j 5.0.3 API, which interacts with the Neo4j 3.3.1 causal cluster consisting of 3 main nodes (1 leader and 2 followers). For better or worse, we also send many custom cypher queries to the database using prepared session.query a la SQL statements. When we do this, we notice that virtually none of our custom Cypher sent via session.query is sent to any of the read-only followers.

I cracked the code and noticed that in Neo4jSession the query method always creates a transaction of type READ_WRITE . Is there a way around this so that our requests are distributed across our cluster correctly?

I also tried marking the appropriate methods with @Transactional(readOnly = true) , but it does not work. When I entered the Neo4jTransactionManager , I see the following line 218:

 private Transaction.Type getTransactionType(TransactionDefinition definition, Neo4jTransactionObject txObject) { Transaction.Type type; if (definition.isReadOnly() && txObject.isNewSessionHolder()) { type = Transaction.Type.READ_ONLY; } else if (txObject.transactionData != null) { type = txObject.transactionData.type(); } else { type = Transaction.Type.READ_WRITE; } return type; } 

What does the second condition, isNewSessionHolder , isNewSessionHolder in the first branch? In the context of one HTTP API call, we call the database at least 2 times, so on the second request, I believe that this condition always returns false.

Given these observations, are there any easy ways for my requests to be read-only?

+5
source share
1 answer

The first part regarding Spring: due to the limitations of Spring AOP, it is not possible to conduct multiple isolated transactions within the same class. A better solution would be to separate the calling code from transactional methods in different classes. Then @Transactional(readOnly = true) will work.

The second part regarding OGM session.query calls: if your unit of work is participating in an existing READ_WRITE transaction, for example, this is due to the @Transactional AOP problem above, there is no way to set the type to READ_ONLY . Because OGM always creates a READ_WRITE transaction by READ_WRITE unless an explicit type is specified.

TL; DR;

There are two solutions to the problem as a whole:

  • Extract the @Transactional methods to another class and leave the caller code in the existing one.
  • Create a Session object manually by entering SessionFactory and create a transaction of type READ_ONLY . (and remove the @Transactional annotation)

(as indicated in the Neo4j user thumbnail)

+1
source

Source: https://habr.com/ru/post/1275347/


All Articles