Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Spring boot 2.0.4.RELEASE fetch eager by default

I'm using spring boot with JPA ( hibernate ) , Before I move to spring boot I was using Spring data JPA with hibernate and the default is to load property values eagerly and to load collections lazily.

in spring boot JPA the following is fetched eagerly by default why ? The roles will be returned inside the user but they should be null

@ManyToMany(cascade = CascadeType.ALL)
@JoinTable(name = "user_role", joinColumns = @JoinColumn(name = "user_id"), inverseJoinColumns = @JoinColumn(name = "role_id"))
private Set<Role> roles;

That's the example I followed https://medium.com/@gustavo.ponce.ch/spring-boot-spring-mvc-spring-security-mysql-a5d8545d837d

And the application.properties I have edited to the follow :

# ===============================
# = JPA / HIBERNATE
# ===============================
spring.jpa.show-sql = true
spring.jpa.hibernate.naming-strategy = org.hibernate.cfg.ImprovedNamingStrategy
spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.MySQL5Dialect

# ==============================================================
# = Spring Security / Queries for AuthenticationManagerBuilder
# ==============================================================
spring.queries.users-query=select email, password, active from user where email=?
spring.queries.roles-query=select u.email, r.role from user u inner join user_role ur on(u.id=ur.user_id) inner join role r on(ur.role_id=r.id) where u.email=?

=========================================================================== I have tried to add this relation in the user Entity :

@Entity
@Table(name = "user")
@Getter
@Setter
public class User {

    @OneToMany(mappedBy = "user")
    private List<Test> tests;
}

the tests will be fetched eagerly in this :

@Transactional
@Override
public List<User> getAllUsers() {
        List<User>users=userRepository.findAll();
    return users;
}

I can't find why this is default instead of lazy loading.

like image 430
Mohammad Karmi Avatar asked Jun 10 '26 09:06

Mohammad Karmi


2 Answers

You are mistaken. Every mapping that ends with toMany is by default fetched lazily.
Copied from the Spring source files:

@Target({METHOD, FIELD})
@Retention(RUNTIME)
public @interface ManyToMany {

    // rest of the annotation properties are omitted for better readability

    FetchType fetch() default LAZY;
}
like image 192
senjin.hajrulahovic Avatar answered Jun 11 '26 21:06

senjin.hajrulahovic


Spring Boot nor Spring Data JPA changes the default behavior of resolving collections lazily. You probably have one of two the situations when using Spring Boot

  1. Previously your @Transactional wasn't properly applied due to wrong configuration
  2. Spring Boot by default enables the OpenEntityManagerInViewInterceptor for controllers.

Spring Boot manages transactions for you and will have the processing of @Transactional turned on by default. So when inspecting the result inside the @Transactional method using a debugger the result will still be retrieved due to an ongoing transaction.

If that isn't the case you are seeing the effects of the OpenEntityManagerInViewInterceptor. Which leads to opening an EntityManager at the start of the request and close it after view rendering.

To disable this behavior (and assuming you are using a recent Spring Boot version) you can disable it by setting the spring.jpa.open-in-view property to false.

spring.jpa.open-in-view=false
like image 28
M. Deinum Avatar answered Jun 11 '26 22:06

M. Deinum



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!