0

I have a problem where I do have @Transactional annotation in my service layer, but also repository layer. I fetch an entity and perform an partial update, then fetch all entities to perform some operation based on that updated field. Unfortunately the field has the old value. How can I solve this problem?

I make it work, when I deleted the @Transactional annotation from the service layer, but it's needed there.

Also does it make sense to mark the whole repository as transactional, or only the UPDATE methods?

  • Repository
@Repository
@Transactional
interface ExampleRepository extends JpaRepository<Ex, Long> {
    @Modifying
    @Query("UPDATE ExampleEntity e SET e.name = :name WHERE e.id IN (:ids)")
    int updateName(@Param("name") String name, @Param("ids") Collection<Long> ids);
}
  • Service
@Service
class ExampleService {

    private final ExampleRepository exampleRepository;

    ExampleService(final ExampleRepository exampleRepository) {
        this.exampleRepository = exampleRepository;
    }

    @Transactional
    public void updateName(Long id) {
        exampleRepository.findById(id).ifPresent(e -> {
            int updated = exampleRepository.updateName("NewName", List.of(e.getId()));
            if(updated > 0) {
                System.out.println("Updated"); // this is executed as updated is > 0
            }

            exampleRepository.findAll(); // returns entity with the old name
        });
    }
}

  • This seems to be an answer to this problem. https://stackoverflow.com/questions/43665090/why-do-we-have-to-use-modifying-annotation-for-queries-in-data-jpa –  Nov 10 '22 at 12:37
  • 1
    You search an entity, by pass the entitymanager by updating the database and do a findall. The findAll finds the existing entity in memory and returns it (instead of using the database one). Why because everything is in a single transaction and thus shares the same `EntityManager` which acts as a 1st level cache. – M. Deinum Nov 10 '22 at 13:25
  • Indeed, `@Modifying` alone does not update the 1st level cache. You have to force it adding `(clearAutomatically = true)`. Becareful : it is going to detach all your entities ! And if your are not sure that other modifications are still pending in memory you add `(flushAutomatically = true)` not to loose them. – Pierre Demeestere Nov 10 '22 at 14:54

0 Answers0