Correct way to get transactions using Spring Data Neo4j's simple object/graph mapping?
Asked Answered
A

1

5

I'm using the simple object/graph mapping in Spring Data Neo4j 2.0, where I perform persistence operations using the Spring Data repository framework. I'm working with the repositories rather than working with the Neo4jTemplate. I inject the repositories into my Spring Web MVC controllers, and the controllers call the repos directly. (No intermediate service layer--my operations are generally CRUDs and finder queries.)

When I do read operations, there are no issues. But when I do write operations, I get "NotInTransactionException". My understanding is that read ops in Neo4j don't require transactions, but write ops do.

What's the best way to get transactions into the picture here, assuming I want to stick with the simple OGM? I'm wanting to use @Transactional, but putting that on the various repository interfaces doesn't work. If I introduce an intermediate service tier in between the controllers and the repositories and then annotate the service beans with @Transactional, then it works, but I'm wondering whether there's a simpler way to do it. Without Spring Data, I'd typically have access to the DAO (repository) implementations, so I'd be able to annotate the concrete DAOs with @Transactional if I wanted to avoid a pass-through service tier. With Spring Data the repos are dynamically generated so that doesn't appear to be an option.

Adit answered 7/1, 2012 at 19:59 Comment(1)
@Transactional at the Repository-Interfaces should work.Kittrell
P
8

First, note that having transactional DAOs is not generally a good practice. But if you don't have a service layer, then let it be on the DAOs.

Then, you can enable declarative transactions. Here's how I did it:

First, define an annotation called @GraphTransactional:

@Retention(RetentionPolicy.RUNTIME)
@Transactional("neo4jTransactionManager")
public @interface GraphTransactional {

}

Update: spring-data-neo4j have added such an annotation, so you can reuse it instead of creating a new one: @Neo4jTransactional

Then, in applicationContext.xml, have the following (where neo4jdb is your EmbeddedGraphDatabase):

<bean id="neo4jTransactionManagerService"
    class="org.neo4j.kernel.impl.transaction.SpringTransactionManager">
    <constructor-arg ref="neo4jdb" />
</bean>
<bean id="neo4jUserTransactionService" class="org.neo4j.kernel.impl.transaction.UserTransactionImpl">
    <constructor-arg ref="neo4jdb" />
</bean>

<bean id="neo4jTransactionManager"
    class="org.springframework.transaction.jta.JtaTransactionManager">
    <property name="transactionManager" ref="neo4jTransactionManagerService" />
    <property name="userTransaction" ref="neo4jUserTransactionService" />
</bean>

<tx:annotation-driven transaction-manager="neo4jTransactionManager" />

Have in mind that if you use another transaction manager as well, you'd have to specify order="2" for this annotation-driven definition, and also have in mind that you won't have two-phase commit if you have one method that is declared to be both sql and neo4j transactional.

Pell answered 7/1, 2012 at 23:11 Comment(4)
there is already @Neo4jTransactional which does exactly that.Kittrell
and the <neo4j:config> already sets up the transaction manager in the way you describe.Kittrell
thanks, I added an update. The annotation wasn't there in previous versions :)Pell
Is there any doc or blog on how to do this with annotations with SDN 3.3.2 ? I've been stuck for a few days on how to have a basic configuration for Neo4J and JPA together #32297176Collado

© 2022 - 2024 — McMap. All rights reserved.