IMDB Transaction handling
From NeoWiki
Contents |
[edit] Neo4j and transactions
With neo4j, every single operation has to be in a transaction. You'd want that anyhow, yes?!
With neo4j, there is no fetch/store cycle other than the transaction itself. This means that the neo4j storage interaction cycle looks like this:
- Begin a transaction.
- Operate on the node space.
- Mark the transaction as successful (or not).
- Finish the transaction.
You have to make sure that every piece of code interacting with the neo4j engine is wrapped in a transaction. By setting the begin and finish points of the transactions, you divide the storage interactions into logical units.
If you return a neo4j node from some method and the caller is going to do operations on this node, the call to the method will also have to be inside of a transaction.
The basic way to implement transactions in neo4j is like in this code snippet:
Transaction tx = neo.beginTx();
try
{
// all neo4j operations that work with the node space
tx.success();
}
finally
{
tx.finish();
}
More information is found at Getting Started Guide#Wrap everything in a transaction and of course in the Transaction class API documentation. Information on nesting transactions is found on the Neo Transactions page.
Neo4j transactions are used to partition the storage interactions into logical units and commit successful transactions.
[edit] Transactions in the IMDB example
[edit] Spring injections
To make the code cleaner, we use the Spring functionality to
configure a transaction manager and invoke it by
using the @Transaction annotation in the code.
Note: The annotations are not as visible when reading the
code as the explicit calling of Transaction
in the snippet above. Don't get fooled by this - the
transactions are still there!
This is how the transactions are set up in the Spring web configuration (src/main/webapp/WEB-INF/imdb-app-servlet.xml):
<tx:annotation-driven /> <bean id="transactionManager" class="org.springframework.transaction.jta.JtaTransactionManager"> <property name="transactionManager" ref="neoTransactionManagerService" /> <property name="userTransaction" ref="neoUserTransactionService" /> </bean> <bean id="neoTransactionManagerService" class="org.neo4j.impl.transaction.SpringTransactionManager" /> <bean id="neoUserTransactionService" class="org.neo4j.impl.transaction.UserTransactionImpl" />
This will make Spring delegate the transaction handling to the neo4j transaction handler.
A typical invocation of transaction handling looks like this:
@Transactional
public void newActors( final List<ActorData> actorList )
{
// code that operates on the node space
}
[edit] Different contexts
In the IMDB example application, we decided not to put the transactions in the domain layer, but let the consumers of it decide on what should go into one transaction.
There are three classes that handle transactions in the application:
-
org.neo4j.apps.imdb.web.ActorFindControllerDelegate -
org.neo4j.apps.imdb.web.MovieFindControllerDelegate -
org.neo4j.apps.imdb.parser.ImdbReaderImpl
The ActorFindControllerDelegate
and MovieFindControllerDelegate
classes provide the actor and movie search pages
content. They start a single transaction for every
time a search is performed.
The ImdbReaderImpl class inserts the bulk IMDB data
into the node space. Every set of data will be inside
one transaction. This makes it possible for the caller
to decide on balancing buffering of data to insert
against transaction performance concerns.
By this design - not handling the transactions in the domain layer - the domain layer can be used in a more flexible way providing possible performance optimizations. Just remember that every single neo4j-operation has to be in a transaction.
Next part: IMDB Inserting Data Index page: overview

