0

Scenario

A Spring Data JPA/Hibernate based application with @Transactional services, thus entities are managed by the persistence provider with no explicit invoking of save/update/persist.

Now, I'd like to implement a read-only repository/service for MyEntity, while also keeping the non-read-only/CRUD ones -- ergo, annotating the entity @Immutable will be too much and would not help.

Approach

Fetching entities within a read-only session (which we reset to non-read-only afterwards), here as a simplified example:

@Entity
public class MyEntity {

   private long id;

   @OneToMany // lazily-loaded as per default
   private List<MyOtherEntity> otherEntities;
}
@Service
public class ReadOnlyService {

   private final Repository repository;
   private final EntityManager entityManager;

   public MyEntity findAllByIds(Collection<Long> ids) {
      return executeInReadOnlySession(() -> repository.findAllById(ids));
   }

   private <T> T executeInReadOnlySession(Supplier<T> operation) {
    Session session = getSession();
    session.setDefaultReadOnly(true);
    T result = operation.get();
    session.setDefaultReadOnly(false);
    return result;
  }

  private Session getSession() {
    return ((EntityManager) entityManager.unwrap(null)).unwrap(Session.class);
  }
}

The issue with this approach

As such, this approach works fine. However, as MyEntity.otherEntities is lazily-loaded, it's not being loaded within the read-only session. Once it's lazily loaded later on, the session has been reset to setDefaultReadOnly(false) and the list items in otherEntities are not immutable. Moreover, MyOtherEntity might have lazily-loaded relations itself.

Question

Is there a solution to make all of MyEntity's lazily-loaded relationships read-only too (and also recursively all of lazily-loaded fields of MyOtherEntity), without having to eagerly-load them within the read-only session?

Pawel Os.
  • 611
  • 8
  • 26

1 Answers1

0

Solution 1

Annotate your service class like this:

@Transactional(readOnly = true)

Solution 2

Make use of JPARepository methods. All reading methods of SimpleJPARepository are already annotated as read-only. Only the save*, delete* and flush methods are annotated for modification. That's what you wanted, right?

SimpleJPARepository is the default implementation of JPARepository interface and will be used after proper auto-configuration of Spring Boot Data. For example when spring-boot-starter-data-jpa dependency is present.

Mar-Z
  • 2,660
  • 2
  • 4
  • 16