Search code examples
spring-boottransactional

Can I commit a portion of an @Transactional sequence?


I have a Spring Boot application, and have a webservice where a user can POST a model of a CollegeCourse instance which includes links between that class and the Students who are taking it. (The data is used to store rows in the association table, since those classes have a many-to-many relationship.) This works fine.

Say the enrollment in the course changes. The User expects to send the same JSON structure to the webservice handling the PUT call. The code took the easy path for updating, first finding and deleting all the existing CollegeCourse-Student links, then saving the new links. (Rather than iterating through the two lists, matching up items.) This part worked also as given.

We then added a uniqueness constraint to the CollegeCourse-Student association table, so that said table could not have a single Student linked to one CollegeCourse multiple times. This crashed and burned. A debugging session revealed the culprit: the delete of the CollegeCourse-Student records did not actually remove them from the database until the transaction completed. Thus, when we tried to add the new links back in, any holdovers from the original POST conflicted with what was already in the database.

The service handling the PUT is preceded by a @Transactional annotation. I tried moving the code to find and delete the associations in a separate method, and tried both @Transactional(propagation=Propagation.REQUIRED) and REQUIRES_NEW, but neither prevented failing the uniqueness constraint. I also added @EnableTransactionManagement to my Application class - same story. Is there a simple solution to my dilemma?


Solution

  • Without knowing exactly what your repository looks like, have you tried to do a manual flush on the entity manager after the deletions?

    Something along the lines of

    entityManager.flush();
    

    Or, if you're using a Spring Data JPA repository, you should be able to define a flush method in that interface and call it.