Announcement Announcement Module
No announcement yet.
Applying transaction boundaries Page Title Module
Move Remove Collapse
Conversation Detail Module
  • Filter
  • Time
  • Show
Clear All
new posts

  • Applying transaction boundaries

    This kind of follows on from this this post here (

    What I am trying to do is have the @Service as my transaction boundary, but from what I can see the transaction boundary is actually being applied only at the repository layer.

    Given this service method:

    public void addFriend(Person firstPerson, Person secondPerson) {

    I end up getting a NotInTransactionException. I thought that my transaction manager wasn't being loaded at all but then I found a curious thing - when I commented out the makeFriendsWith method, I could run the the code without exception. Does this mean that the transaction boundary is not being properly applied to the service?

    FYI - inside the makeFriendsWith method, a new Friendship method is being created and added to the original Person's list of friends. Presumably this is kicking off a transaction which for some reason doesn't have an open transaction around it.

    Bug, or just coded wrong on my behalf?


  • #2
    But you have tx management setup correctly ? And your @Service is injected by Spring?

    Can you perhaps share your project for us to check?

    Thanks Michael


    • #3
      Thanks Michael,

      Just putting a tets up into GitHub now. The dependencies are almost the same as the hello world example, and my app context is as follows:

      <?xml version="1.0" encoding="UTF-8" standalone="no"?>
      <beans xmlns=""

      <contextroperty-placeholder location="classpath:META-INF/"


      <context:component-scan base-package=""/>

      <neo4j:config graphDatabaseService="neo4jGraphDatabase"/>
      <neo4j:repositories base-package=" .graph"/>

      <!--<bean id="graph" class="com.tinkerpop.blueprints.pgm.impls.neo4j.Ne o4jGraph">-->
      <!--<constructor-arg value="/tmp/graph.db"/>-->

      <bean id="wrappingNeoServerBootstrapper" class="org.neo4j.server.WrappingNeoServerBootstrap per" init-method="start"
      <constructor-arg ref="neo4jGraphDatabase"/>

      <bean id="neo4jGraphDatabase" class="${graph.graphClassName}"
      <constructor-arg value="${graph.path}"/>
      <constructor-arg ref="neo4j-properties"/>

      <bean name="neo4j-properties" class="java.util.HashMap">
      <constructor-arg index="0">
      <entry key="allow_store_upgrade">
      <entry key="ha.machine_id" value="${}"/>
      <entry key="ha.server" value="zoo1:${ha.server.port}"/>
      <entry key="ha.zoo_keeper_servers" value="${zookeeper.servers}"/>
      <entry key="enable_remote_shell" value="port=1331"/>
      <entry key="ha.pull_interval" value="1"/>

      <tx:annotation-driven mode="aspectj" transaction-manager="transactionManager"/>


      Not sure if perhaps my tx declaration is wrong but I'll upload the test now.



      • #4
        Annoyingly I've written a bunch of unit tests which all work perfectly with my sample application on github, which makes what I am running into even weirder. I've put the github stuff in as I think it illustrates it.

        My service is at - We simply get or create two nodes, then relate them.

        The test for this is at It is super simple, and just tries to show I don't get a not in transaction exception.

        The domain model is at Referring a member simply adds them to that list of referees.

        As I said, all this code passes, but in my actual work project, the process of performing the add inside the domain class (it's definitely this - I comment it out and all works) is what causes the exception. Is there any way that at this point we have somehow become detached from the wrapping transaction? And if so, what would cause this? My production code is almost identical to the gh stuff.

        My workaround for now I guess could be to use the template to save the relationship directly, but I'm still very confused as to how i have ended up outside of a transaction.



        • #5
          Coded wrong. The 2 objects are retrieved outside of the transaction (in a test method in general there is a transaction around the test method making the 2 object retrieved inside the same transaction). The whole unit of work (getting the persons, adding friends) should be a single transaction. I suspect the calling code is first retrieving the persons then call this code.

          Also make sure that transactions are actually applied, in your stacktrace there should be a TransactionInterceptor somewhere.
          Last edited by Marten Deinum; Jan 26th, 2012, 05:42 AM.


          • #6
            I've tried to reproduce this in a project on GitHub and annoyingly it always seems to work there.

            I am confident everything is fine with my Spring setup (I've got tests that prove that a simple save works and a simple retrieve from the repository works).

            I am injecting the service into my test, much like this test here - and I know for sure the transactionality being applied is from my service as my test class has no transactional annotations.

            I think the problem is that somehow my transaction seems to be missing when I do anything to the relationship. Consider my service code:

            public void refer(Long referer, Long referee) {
            Member refererMember = getOrCreateMember(referer);
            Member refereeMember = getOrCreateMember(referee);
            refererMember.refer(refereeMember); // Add the relationship

            public Member getOrCreateMember(long memberId) {

            Member member = memberRepository.findByPropertyValue("memberId", memberId);

            if (member == null) {
            member = Member(memberId));

            return member;

            That commented line is the one that throws the NotInTransactionException (if it gets commented out the entities are persisted, just not the relationship). Interestingly, the exact same thing happens when I use the template directly to save the relationship (again, doesn't fail in my Github code, only on the production code).

            Are there any scenarios you can think of at all where the transaction is not available for persisting the relationship?


            • #7
              If it helps, this is the particular stack trace exception at this point:

              at org.neo4j.kernel.impl.persistence.PersistenceManag er.getResource(
              at org.neo4j.kernel.impl.persistence.PersistenceManag er.relationshipCreate(
              at org.neo4j.kernel.impl.core.NodeManager.createRelat ionship(
              at org.neo4j.kernel.impl.core.NodeImpl.createRelation shipTo(
              at org.neo4j.kernel.impl.core.NodeProxy.createRelatio nshipTo(
              at ityStateHandler.createRelationship(EntityStateHand
              at ityStateHandler.useOrCreateState(EntityStateHandle
              at 4jEntityConverterImpl.write(Neo4jEntityConverterIm
              at 4jEntityPersister$CachedConverter.write(Neo4jEntit
              at 4jEntityPersister.persist(Neo4jEntityPersister.jav a:244)
              at 4jEntityPersister.persist(Neo4jEntityPersister.jav a:227)
              at elationshipEntityFieldAccessorFactory$OneToNRelati onshipEntityFieldAccessor.persistEntities(OneToNRe
              at elationshipEntityFieldAccessorFactory$OneToNRelati onshipEntityFieldAccessor.setValue(OneToNRelations
              at FieldAccessorSet.updateValue(ManagedFieldAccessorS
              at FieldAccessorSet.update(ManagedFieldAccessorSet.ja va:78)
              at FieldAccessorSet.add( 104)


              • #8
                FYI, I've actually found a slight difference - reading through the docs:

                It must not be a primitive type because then the "non-attached" case can not be represented as the default value 0 would point to the reference node. Please make also sure that an equals() and hashCode() method have to be provided which take the id field into account (and also handle the "non-attached", null case).

                I'm not factoring the graphId into hashCode and equals of my objects. I had purposely left this out but I'll add it in now with the recommendations. Can't imagine this is the fix, but it's a worthwhile thing to do anyways.


                • #9
                  Fixed - the test wasn't working properly because in the test context I was missing:

                  <tx:annotation-driven mode="proxy"/>

                  and the non test wasn't working because I defined the annotation mode in the graph bean as such:

                  <tx:annotation-driven mode="aspectj" transaction-manager="transactionManager"/>


                  • #10
                    Hello Michael,

                    I have the same issue... Using is working in a @Transactional @Test method, but not in a (non test) @Transactional @Service method. I had the <tx:annotation-driven mode="proxy"/> set up in all cases, as well as the annotation-config, spring-configured, component-scan, and neo4j config things.

                    In the code below, as soon as the call is made, that NotInTransactionException is thrown.

                    public class SimpleDatabasePopulator {

                    Neo4jOperations template;

                    public void populateDatabase() {
                    SimpleCustomer customer = SimpleCustomer("A customer"));
                    SimpleContact contact = SimpleContact("A contact"));
                    template.createRelationshipBetween(contact, customer, SimpleRelation.class, "CONTACT_OF_CUSTOMER", false);

                    Anything else is needed to configure transactions? Did you have to do anything else that could fix this, like, do we really have to override equals and hashCode?

                    Thank you,


                    • #11
                      Nothing else really needed. Could the both of you do me a favor and configure
                      <tx:annotation-driven mode="aspectj"/> ?

                      and for good measure
                      <tx:annotation-driven mode="aspectj" transaction-manager="neo4jTransactionManager"/> ?

                      You know that the proxy tx-mode creates a subclass that is overriding the methods and calls super or a delegate instance with tx-boundaries around that call (at least for classes, uses dynamic proxy for interfaces imho). Perhaps that's somehow messing up the tx-propagation?

                      MichaelMC could you please summarize your current state, I'm a bit confused by the many dimensions, 2 projects and test + service, too much for my little brain.




                      • #12
                        Hi Michael H.,

                        Now I have NotInTransactionException in both cases. I'll continue the investigation tomorrow.



                        • #13
                          By the way, I tried running your tests here, the MemberServiceTest passes, and the MemberServiceImplTest fails with:

                          org.springframework.beans.factory.BeanCreationExce ption: Error creating bean with name 'com.michael.service.MemberServiceImplTest': Injection of resource dependencies failed; nested exception is org.springframework.beans.factory.NoSuchBeanDefini tionException: No matching bean of type [com.michael.service.MemberServiceImpl] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {@javax.annotation.Resource(shareable=true, mappedName=, description=, name=, type=class java.lang.Object, authenticationType=CONTAINER)}
                          at org.springframework.context.annotation.CommonAnnot ationBeanPostProcessor.postProcessPropertyValues(C
                          at AutowireCapableBeanFactory.populateBean(AbstractAu
                          at AutowireCapableBeanFactory.autowireBeanProperties(
                          at yInjectionTestExecutionListener.injectDependencies ( )
                          at yInjectionTestExecutionListener.prepareTestInstanc e( )
                          at org.springframework.test.context.TestContextManage r.prepareTestInstance(
                          at org.springframework.test.context.junit4.SpringJUni t4ClassRunner.createTest(SpringJUnit4ClassRunner.j ava:211)
                          at org.springframework.test.context.junit4.SpringJUni t4ClassRunner$1.runReflectiveCall(SpringJUnit4Clas
                          at org.junit.internal.runners.model.ReflectiveCallabl
                          at org.springframework.test.context.junit4.SpringJUni t4ClassRunner.methodBlock(SpringJUnit4ClassRunner. java:290)
                          at org.springframework.test.context.junit4.SpringJUni t4ClassRunner.runChild(SpringJUnit4ClassRunner.jav a:231)
                          at org.junit.runners.BlockJUnit4ClassRunner.runChild(
                          at org.junit.runners.ParentRunner$ java:231)
                          at org.junit.runners.ParentRunner$1.schedule(ParentRu
                          at org.junit.runners.ParentRunner.runChildren(ParentR
                          at org.junit.runners.ParentRunner.access$000(ParentRu
                          at org.junit.runners.ParentRunner$2.evaluate(ParentRu
                          at org.springframework.test.context.junit4.statements .RunBeforeTestClassCallbacks.evaluate(RunBeforeTes
                          at org.springframework.test.context.junit4.statements .RunAfterTestClassCallbacks.evaluate(RunAfterTestC
                          at va:300)
                          at org.springframework.test.context.junit4.SpringJUni )
                          at org.eclipse.jdt.internal.junit4.runner.JUnit4TestR
                          at org.eclipse.jdt.internal.junit.runner.TestExecutio
                          at org.eclipse.jdt.internal.junit.runner.RemoteTestRu nner.runTests(
                          at org.eclipse.jdt.internal.junit.runner.RemoteTestRu nner.runTests(
                          at org.eclipse.jdt.internal.junit.runner.RemoteTestRu
                          at org.eclipse.jdt.internal.junit.runner.RemoteTestRu nner.main(
                          Caused by: org.springframework.beans.factory.NoSuchBeanDefini tionException: No matching bean of type [com.michael.service.MemberServiceImpl] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {@javax.annotation.Resource(shareable=true, mappedName=, description=, name=, type=class java.lang.Object, authenticationType=CONTAINER)}
                          at istableBeanFactory.raiseNoSuchBeanDefinitionExcept ion(
                          at istableBeanFactory.doResolveDependency(DefaultList
                          at istableBeanFactory.resolveDependency(DefaultListab
                          at org.springframework.context.annotation.CommonAnnot ationBeanPostProcessor.autowireResource(CommonAnno
                          at org.springframework.context.annotation.CommonAnnot ationBeanPostProcessor.getResource(CommonAnnotatio
                          at org.springframework.context.annotation.CommonAnnot ationBeanPostProcessor$ResourceElement.getResource ToInject( 9)
                          at org.springframework.beans.factory.annotation.Injec tionMetadata$InjectedElement.inject(InjectionMetad
                          at org.springframework.beans.factory.annotation.Injec tionMetadata.inject(
                          at org.springframework.context.annotation.CommonAnnot ationBeanPostProcessor.postProcessPropertyValues(C
                          ... 26 more


                          • #14
                            I'm a little busy today but I'll see if I can make the project on GitHub fail with the same errors I was seeing, presumably if you've all got a project you can run and see fail it might make it easier to pinpoint exactly what we've done wrong!

                            In summary for me, and the case in point here is a single method in a service injected with a repository.:

                            - Within the method, all calls to my injected WERE being executed in a transaction
                            - Within the method, the call to add a relationship to a domain model was NOT being executed in a transaction and threw the relevant exception.

                            When I browse into the CRUDRepository source code, I notice that the relevant save methods are marked as transactional. I don't know if that means that transactionality was always applying at that level, just not at my service level.


                            • #15
                              Hi All,

                              Regarding the issue I got related to NotInTransactionException, this was due to component scanning, for those of you using Spring MVC.

                              The root-context must have the base package defined, excluding controllers:

                              <context:component-scan base-package="">
                                  <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
                              and the servlet-context must have the appropriate controller subpackage in it, not the root base package.

                              <context:component-scan base-package=""/>
                              After changing that, it went through @Transactional code. Hope this will help someone some day. And good job on Spring Data Neo4j project.

                              Thanks all,