Issue
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
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;
}
}
Solution
@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.
Answered By - Paul Warren
Answer Checked By - Timothy Miller (JavaFixing Admin)