leonaugust
leonaugust

Reputation: 312

Spring Content. Hibernate executes 3 queries to fetch image for each product

I have a products page. Each listed product has its own image. To display it on view I use this line <img th:src="@{/data/{id}(id=${product.id})}"

When I'm going to the endpoint to see products, Hibernate generates 7 queries instead of 1.

Hibernate: 
    select
        product0_.id as id1_0_,
        product0_.content_id as content_2_0_,
        product0_.content_length as content_3_0_,
        product0_.mime_type as mime_typ4_0_,
        product0_.name as name5_0_ 
    from
        product product0_
Hibernate: 
    select
        product0_.id as id1_0_0_,
        product0_.content_id as content_2_0_0_,
        product0_.content_length as content_3_0_0_,
        product0_.mime_type as mime_typ4_0_0_,
        product0_.name as name5_0_0_ 
    from
        product product0_ 
    where
        product0_.id=?
Hibernate: 
    select
        product0_.id as id1_0_0_,
        product0_.content_id as content_2_0_0_,
        product0_.content_length as content_3_0_0_,
        product0_.mime_type as mime_typ4_0_0_,
        product0_.name as name5_0_0_ 
    from
        product product0_ 
    where
        product0_.id=?
Hibernate: 
    select
        product0_.id as id1_0_0_,
        product0_.content_id as content_2_0_0_,
        product0_.content_length as content_3_0_0_,
        product0_.mime_type as mime_typ4_0_0_,
        product0_.name as name5_0_0_ 
    from
        product product0_ 
    where
        product0_.id=?
Hibernate: 
    select
        product0_.id as id1_0_0_,
        product0_.content_id as content_2_0_0_,
        product0_.content_length as content_3_0_0_,
        product0_.mime_type as mime_typ4_0_0_,
        product0_.name as name5_0_0_ 
    from
        product product0_ 
    where
        product0_.id=?
Hibernate: 
    select
        product0_.id as id1_0_0_,
        product0_.content_id as content_2_0_0_,
        product0_.content_length as content_3_0_0_,
        product0_.mime_type as mime_typ4_0_0_,
        product0_.name as name5_0_0_ 
    from
        product product0_ 
    where
        product0_.id=?
Hibernate: 
    select
        product0_.id as id1_0_0_,
        product0_.content_id as content_2_0_0_,
        product0_.content_length as content_3_0_0_,
        product0_.mime_type as mime_typ4_0_0_,
        product0_.name as name5_0_0_ 
    from
        product product0_ 
    where
        product0_.id=?

Probably, the problem is connected to the way how I receive the image on the page. I assume it happens like that: ProductRepository normally executes 1 query to get list of products. Then to show image on page Spring executes 3 queries for each product. Also I noticed that endpoint with image "/data/1" produces 3 queries.

Hibernate: 
    select
        product0_.id as id1_0_0_,
        product0_.content_id as content_2_0_0_,
        product0_.content_length as content_3_0_0_,
        product0_.mime_type as mime_typ4_0_0_,
        product0_.name as name5_0_0_ 
    from
        product product0_ 
    where
        product0_.id=?
Hibernate: 
    select
        product0_.id as id1_0_0_,
        product0_.content_id as content_2_0_0_,
        product0_.content_length as content_3_0_0_,
        product0_.mime_type as mime_typ4_0_0_,
        product0_.name as name5_0_0_ 
    from
        product product0_ 
    where
        product0_.id=?
Hibernate: 
    select
        product0_.id as id1_0_0_,
        product0_.content_id as content_2_0_0_,
        product0_.content_length as content_3_0_0_,
        product0_.mime_type as mime_typ4_0_0_,
        product0_.name as name5_0_0_ 
    from
        product product0_ 
    where
        product0_.id=?

How to optimize this process and execute less queries? Project to demonstrate the problem

https://github.com/leonaugust/hibernate-problem

Code:

@SpringBootApplication
@Controller
@EnableJpaRepositories
public class HibernateProblemApplication {

  @Autowired
  private ProductRepository repository;

  public static void main(String[] args) {
    SpringApplication.run(HibernateProblemApplication.class, args);
  }

  @GetMapping("/")
  public String getAll(Model model) {
    model.addAttribute("products", repository.findAll());
    return "products";
  }

  @Bean
  public CommandLineRunner uploadImages(ProductRepository repository,
      ProductImageStore store) {
    return (args) -> {
      Product chicken = new Product("Chicken");
      store.setContent(chicken, this.getClass().getResourceAsStream("/img/chicken.jpg"));
      repository.save(chicken);

      Product goose = new Product("Goose");
      store.setContent(goose, this.getClass().getResourceAsStream("/img/goose.jpg"));
      repository.save(goose);
    };
  }

}


@StoreRestResource(path = "data")
@Repository
public interface ProductImageStore extends ContentStore<Product, String> {
}


@Repository
public interface ProductRepository extends JpaRepository<Product, Long> {

}


@Entity
public class Product {
  @Id
  @GeneratedValue(strategy = GenerationType.AUTO)
  private Long id;

  private String name;

  @ContentId
  private String contentId;

  @ContentLength
  private Long contentLength = 0L;

  @MimeType
  private String mimeType = "text/plain";

  public Product(String name) {
    this.name = name;
  }

}

Upvotes: 1

Views: 132

Answers (1)

Paul Warren
Paul Warren

Reputation: 2479

@leonaugust thanks for bringing this to my attention. Turns out our rest controller wasn't very smart and was doing more queries than it needed to. Fixed in the 1.2.1 release.

Upvotes: 1

Related Questions