Search code examples
javaspring-bootneo4jspring-data-neo4j-4

Using SpringBoot with Neo4J: Updating node creates duplicate node


I am trying to update a node on Neo4J, but what ends up happening is that it creates a duplicate Node. I read that the update has to be in a single transaction and I added @Transactional, but still same result. Here is what I have. I tried the approach of reading and deleting the old node, and saving the new one and it appears to be working. But, I think that is not the right approach. Why the @Transactional annotation not working. Thank you.

@EnableNeo4JRepositories(com.example.graph.repo)
@EnableTransactionManagement
@org.springframework.contect.annotation.Configuration
public class Neo4JConfig {
   @Bean
   public Configuration configuration() {
       Configuration cfg = new Configuration();
       cfg.driverConfiguration()                 
       .setDriverClassName("org.neo4j.ogm.drivers.http.driver.HttpDriver")
       .setURI("http://neo4j:neo4j@localhost:7474");
       return cfg;
    }

    @Bean 
    public SessionFactory sessionFactory() {
       return new SessionFactory(configuration(), "com.example");
    }

    @Bean
    public Neo4jTransactionManager transactionManager() {
       return new Neo4JTransactionManager(sessionFactory());
    }
}

@Service
public class UserService{
   @Autowired
   UserRepository userRepository;

   @Transactional
   public void updateUser(User user) {
       User existingUser = userRepository.getExistingUser(user.getUserName());
       if(existingUser != null ) {
           user.setSomeValue(existingUser.getSomeValue());
           userRepository.save(user);
       }
   }
}

Solution

  • Spring AOP uses JDK Proxy mechanism by default. It means that you must invoke @Transactional method via interface method.

    So you should split your service into interface UserService and implementation (say UserServiceImpl), autowire the interface into the code where you currently autowire the impementation, and then invoke transactional method via interface.

    P.S. Another approach is to force Spring to use CGLIB as long as this mechanism is not limited to interfaces. More details for both mechanisms https://docs.spring.io/spring/docs/3.0.0.M3/reference/html/ch08s06.html