Search code examples
javaspringtransactionalspring-data-neo4j-4neo4j-ogm

SDN Migration to 4.2: How does @Transactional works?


I'm trying to upgrade versions of SDN (4.2.0.M1) and neo4j-ogm (2.0.5) to the latest snapshots 4.2.0.BUILD-SNAPSHOT and 2.1.0-SNAPSHOT.

Following the migration guide and some advises from other SO questions, I've wrapped all methods that interact with neo4j session with @Transactional. It's working fine with most of the cases, but there still are some exceptions (Transaction is not current for this thread) that I cannot understand.

Let me give an example:

@Service
public class ContactServiceImpl implements ContactService {

    @Inject
    private Session session;

    //...

    @Override
    @Transactional
    public void addContact(String userId, String contactId) {
        Contact contact = new Contact();
        // Fill contact data

        session.save(contact);
    }

    @Override
    public void addContacts(String userId, Set<User> newContacts) {
        for (User contact : CollectionUtils.emptyIfNull(newContacts)) {
            addContact(userId, contact.getId());
        }
    }   
}

Here I've only annotated with @Transaction the addContact method, because It's the only one that interacts direcly with SDN, at least this was my thought :)

However, If I call the addContacts method, which simply iterates a list and call the annotated addContact method, It fails with the exception mentioned before. If I also annotate this method, it simply works well, but I don't understand why. Maybe I'm missing some basics about spring @Transactional annotation behaviour, so sorry if it's a brainless question.

Can anyone clarify why I need to annotate both methods? Thanks in advance


Solution

  • @Transactional is a bit more complicated than most people think. What looks like it should work actually doesn't and sometimes vice versa.

    In your case you have hit an unfriendly Spring issue: not understanding how @Transactional AOP proxying works when calling transactional methods from within the same class.

    This snippet from the official documenation is a good starting point to get a rough idea about the basics of Spring's transaction proxying.

    A quick search of StackOverflow brought me this answer which does a great job of explaining the phenomenon you are seeing.

    Note: As of version 4.2, SDN now fully implements the Spring Transaction Platform.