Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How does the FetchMode work in Spring Data JPA

I do have a relation between three model object in my project (model and repository snippets in the end of the post.

When I call PlaceRepository.findById it does fire three select queries:

("sql")

  1. SELECT * FROM place p where id = arg
  2. SELECT * FROM user u where u.id = place.user.id
  3. SELECT * FROM city c LEFT OUTER JOIN state s on c.woj_id = s.id where c.id = place.city.id

That's rather unusual behavior (for me). As far as I can tell after reading Hibernate documentation it should always use JOIN queries. There is no difference in the queries when FetchType.LAZY changed to FetchType.EAGER in the Place class (query with additional SELECT), the same for the City class when FetchType.LAZY changed to FetchType.EAGER (query with JOIN).

When I use CityRepository.findById suppressing fires two selects:

  1. SELECT * FROM city c where id = arg
  2. SELECT * FROM state s where id = city.state.id

My goal is to have a the sam behavior in all situations (either always JOIN or SELECT, JOIN preferred though).

Model definitions:

Place:

@Entity @Table(name = "place") public class Place extends Identified {      @Fetch(FetchMode.JOIN)     @ManyToOne(fetch = FetchType.LAZY)     @JoinColumn(name = "id_user_author")     private User author;      @Fetch(FetchMode.JOIN)     @ManyToOne(fetch = FetchType.LAZY)     @JoinColumn(name = "area_city_id")     private City city;     //getters and setters } 

City:

@Entity @Table(name = "area_city") public class City extends Identified {      @Fetch(FetchMode.JOIN)     @ManyToOne(fetch = FetchType.LAZY)     @JoinColumn(name = "area_woj_id")     private State state;     //getters and setters } 

Repositories:

PlaceRepository

public interface PlaceRepository extends JpaRepository<Place, Long>, PlaceRepositoryCustom {     Place findById(int id); } 

UserRepository:

public interface UserRepository extends JpaRepository<User, Long> {         List<User> findAll();     User findById(int id); } 

CityRepository:

public interface CityRepository extends JpaRepository<City, Long>, CityRepositoryCustom {         City findById(int id); } 
like image 265
SirKometa Avatar asked Apr 13 '15 09:04

SirKometa


People also ask

How does findById work in JPA?

Its findById method retrieves an entity by its id. The return value is Optional<T> . Optional<T> is a container object which may or may not contain a non-null value. If a value is present, isPresent returns true and get returns the value.

How does Spring data JPA works internally?

Spring then parses the method name and creates a query for it. Here is a simple example of a query that loads a Book entity with a given title. Internally, Spring generates a JPQL query based on the method name, sets the provided method parameters as bind parameter values, executes the query and returns the result.

What is FetchMode select?

The Hibernate FetchMode. SELECT generates a separate query for each Order that needs to be loaded. In our example, that gives one query to load the Customers and five additional queries to load the orders collection. This is known as the n + 1 select problem. Executing one query will trigger n additional queries.


1 Answers

I think that Spring Data ignores the FetchMode. I always use the @NamedEntityGraph and @EntityGraph annotations when working with Spring Data

@Entity @NamedEntityGraph(name = "GroupInfo.detail",   attributeNodes = @NamedAttributeNode("members")) public class GroupInfo {    // default fetch mode is lazy.   @ManyToMany   List<GroupMember> members = new ArrayList<GroupMember>();    … }  @Repository public interface GroupRepository extends CrudRepository<GroupInfo, String> {    @EntityGraph(value = "GroupInfo.detail", type = EntityGraphType.LOAD)   GroupInfo getByGroupName(String name);  } 

Check the documentation here

like image 104
wesker317 Avatar answered Sep 18 '22 19:09

wesker317