0

I'm trying to move away from manually-managed transactions to annotation based transactions in my Neo4j application.

I've prepared annotation-based Spring configuration file:

@Configuration
@EnableNeo4jRepositories("xxx.yyy.neo4jplanetspersistence.repositories")
@ComponentScan(basePackages = "xxx.yyy")
@EnableTransactionManagement
public class SpringDataConfiguration extends Neo4jConfiguration      
    implements TransactionManagementConfigurer{

public SpringDataConfiguration() {
    super();
    setBasePackage(new String[] {"xxx.yyy.neo4jplanetspojos"});
}

@Bean
public GraphDBFactory graphDBFactory(){
    GraphDBFactory graphDBFactory = new GraphDBFactory();

    return graphDBFactory;
}

@Bean
public GraphDatabaseService graphDatabaseService() {
    return graphDBFactory().getTestGraphDB(); //new GraphDatabaseFactory().newEmbeddedDatabase inside
}   

@Override
public PlatformTransactionManager annotationDrivenTransactionManager() {
    return neo4jTransactionManager(graphDatabaseService());
}  


}

I've marked my repositories with @Transactional:

@Transactional
public interface AstronomicalObjectRepo extends   
  GraphRepository<AstronomicalObject>{

}

I've marked my unit test classes and test methods with @Transactional and commented old code that used to manually manage transactions:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = {SpringDataConfiguration.class}, 
   loader = AnnotationConfigContextLoader.class)
@Transactional
public class AstronomicalObjectRepoTest {

@Autowired
private AstronomicalObjectRepo repo;


@Autowired
private Neo4jTemplate neo4jTemplate;   

(...)

@Test @Transactional
public void testSaveAndGet() {
   //try (Transaction tx =   
   //neo4jTemplate.getGraphDatabaseService().beginTx()) {


        AstronomicalObject ceres = new AstronomicalObject("Ceres", 
           1.8986e27, 142984000, 9.925);
        repo.save(ceres); //<- BANG! Exception here


        (...)

        //tx.success();
    //}

}

After that change the tests do not pass. I receive: org.springframework.dao.InvalidDataAccessApiUsageException: nested exception is org.neo4j.graphdb.NotInTransactionException

I have tried many different things (explicitly naming transaction manager in @Transactional annotation, changing mode in @EnableTransactionManagment...), nothing helped.

Will be very grateful for a clue about what I'm doing wrong.

Thanks in advance!

cichystefan
  • 328
  • 2
  • 10
  • Where are you declaring your transaction management and datasource??? – We are Borg Jul 24 '15 at 07:22
  • Neo4jConfiguration class which I extend does most of the work. It creates "neo4jTransactionManager" bean which I use in my "annotationDrivenTransactionManager" method to precisely define it as my default tx manager (although @EnableTransactionManagement should be able to discover it by itself, according to docs). I define "graphDatabaseService" bean by myself. It's embedded neo4j graph database. It works properly if transactions are managed by hand. – cichystefan Jul 24 '15 at 07:45
  • Why dont you put the complete code inside that class instead of those round brackets you have... Right now all we can see is annotations...And it's not helpful to isolate the problem – We are Borg Jul 24 '15 at 07:47
  • I didn't want to dim the problem with too much code. But pasted complete configuration now, hope it will help ... – cichystefan Jul 24 '15 at 07:57
  • Debugger says that Neo4jConfiguration's bean "neo4jTransactionManager" returns "PlatformTransactionManager" object that has NullTransactionManager inside. Seems like it may be the cause. Will try to investigate sources and find out why that kind of problem happens ... – cichystefan Jul 27 '15 at 10:16

1 Answers1

1

I found the reason... SDN does not support newest Neo4j in the terms of transaction. I believe it is because SpringTransactionManager in neo4j-kernel has gone in 2.2+ releases, but not 100% sure.

On github we can see that 7 hours ago the change was made to fix it: https://github.com/spring-projects/spring-data-neo4j/blob/master/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/config/JtaTransactionManagerFactoryBean.java

A quick fix that worked for me was to override neo4jTransactionManager method from Neo4jConfiguration in my configuration, using Neo4jEmbeddedTransactionManager class:

    @Override
public PlatformTransactionManager neo4jTransactionManager(GraphDatabaseService graphDatabaseService) {
    Neo4jEmbeddedTransactionManager newTxMgr = new Neo4jEmbeddedTransactionManager(graphDatabaseService());
    UserTransaction userTransaction = new UserTransactionAdapter( newTxMgr );

    return new JtaTransactionManager( userTransaction, newTxMgr );
}
cichystefan
  • 328
  • 2
  • 10