Question

I'm currently having the issue that the @Transactional annotation doesn't seem to start a transaction for Neo4j, yet (it doesn't work with any of my @Transactional annotated methods, not just with the following example).

Example:

I have this method (UserService.createUser), which creates a user node in the Neo4j graph first and then creates the user (with additional information) in a MongoDB. (MongoDB doesn't support transactions, thus create the user-node first, then insert the entity into MongoDB and commit the Neo4j-transaction afterwards).

The method is annotated with @Transactional yet a org.neo4j.graphdb.NotInTransactionException is thrown when it comes to creating the user in Neo4j.

Here is about my configuration and coding, respectively:

Code based SDN-Neo4j configuration:

@Configuration
@EnableTransactionManagement                        // mode = proxy
@EnableNeo4jRepositories(basePackages = "graph.repository")
public class Neo4jConfig extends Neo4jConfiguration {
    private static final String DB_PATH = "path_to.db";
    private static final String CONFIG_PATH = "path_to.properties";

    @Bean(destroyMethod = "shutdown")
    public GraphDatabaseService graphDatabaseService() {
        return new GraphDatabaseFactory().newEmbeddedDatabaseBuilder(DB_PATH)
            .loadPropertiesFromFile(CONFIG_PATH).newGraphDatabase();
    }
}

Service for creating the user in Neo4j and the MongoDB:

@Service
public class UserService {
    @Inject
    private UserMdbRepository mdbUserRepository;    // MongoRepository
    @Inject
    private Neo4jTemplate neo4jTemplate;

    @Transactional
    public User createUser(User user) {
        // Create the graph-node first, because if this fails the user
        // shall not be created in the MongoDB
        this.neo4jTemplate.save(user);              // NotInTransactionException is thrown here
        // Then create the MongoDB-user. This can't be rolled back, but
        // if this fails, the Neo4j-modification shall be rolled back too
        return this.mdbUserRepository.save(user);
    }

    ...
}

Side-notes:

  • I'm using spring version 3.2.3.RELEASE and spring-data-neo4j version 2.3.0.M1
  • UserService and Neo4jConfig are in separate Maven artifacts
  • Starting the server and SDN reading operations work so far, I'm just having troubles with writing operations
  • I'm currently migrating our project from the tinkerpop-framework to SDN-Neo4j. This user creation-process has worked before (with tinkerpop), I just have to make it work again with SDN-Neo4j.
  • I'm running the application in Jetty

Does anyone have any clue why this is not working (yet)?

I hope, this information is sufficient. If anything is missing, please let me know and I'll add it.


Edit:

I forgot to mention that manual transaction-handling works, but of course I'd like to implement it the way "as it's meant to be".

    public User createUser(User user) throws ServiceException {
        Transaction tx = this.graphDatabaseService.beginTx();
        try {
            this.neo4jTemplate.save(user);
            User persistantUser = this.mdbUserRepository.save(user);
            tx.success();
            return persistantUser;
        } catch (Exception e) {
            tx.failure();
            throw new ServiceException(e);
        } finally {
            tx.finish();
        }
    }
Était-ce utile?

La solution

Thanks to m-deinum I finally found the issue. The problem was that I scanned for those components / services in a different spring-configuration-file, than where I configured SDN-Neo4j. I moved the component-scan for those packages which might require transactions to my Neo4jConfig and now it works

@Configuration
@EnableTransactionManagement                        // mode = proxy
@EnableNeo4jRepositories(basePackages = "graph.repository")
@ComponentScan({
    "graph.component",
    "graph.service",
    "core.service"
})
public class Neo4jConfig extends Neo4jConfiguration {
    private static final String DB_PATH = "path_to.db";
    private static final String CONFIG_PATH = "path_to.properties";

    @Bean(destroyMethod = "shutdown")
    public GraphDatabaseService graphDatabaseService() {
        return new GraphDatabaseFactory().newEmbeddedDatabaseBuilder(DB_PATH)
            .loadPropertiesFromFile(CONFIG_PATH).newGraphDatabase();
    }
}

I still will have to separate those components / services which require transactions from those which don't, though. However, this works for now.

I assume that the issue was that the other spring-configuration-file (which included the component-scan) was loaded before Neo4jConfig, since neo4j:repositories has to be put before context:component-scan. (See Note in Example 20.26. Composing repositories http://static.springsource.org/spring-data/data-neo4j/docs/current/reference/html/programming-model.html#d0e2948)

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top