Search code examples
javaspringkotlinspring-data-jpaspring-cache

Spring Data JPA - How to cache entity, which is included in many of other entities


I use Spring Data JPA to get entities from repositories. I have specific entity called Category, which can be included in Offer, Project and User. Every time I load some of these entities from JpaRepository, Spring makes other requests to fetch Category. So, Partner entity looks like this:

@Entity
class Project(...) {
    constructor() : this(...)

    @Id
    var id: String = IDGenerator.longId()

    @ManyToMany
    var categories: MutableList<Category> = mutableListOf()
    @ManyToOne
    var mainCategory: Category? = null

    //other fiels
}

Category looks like this:

@Entity
class Category(var name: String,
                var icon: String) {
    constructor() : this("", "")

    @Id
    var id: String = IDGenerator.longId()
    var marker: String = "default-category.png"
    @ElementCollection
    var defaultImg: MutableList<String> = mutableListOf("default.jpg")
}

How can I cache categories and make them load not from DB, by ID?

P.S. There are just around 40-50 of categories in project.


Solution

  • You want to use hibernate "second level cache"

    1 Add one of second level cache libraries to your pom. I prefer ehcache, but you can use any other.

    <dependency>
        <groupId>org.hibernate</groupId>
        <artifactId>hibernate-ehcache</artifactId>
        <!--Your hibernate version-->
        <version>5.2.2.Final</version> 
    </dependency>
    

    2 Enable the second level cache persistence.xml

    <properties>
        ...
        <property name="hibernate.cache.use_second_level_cache" value="true"/>
        <property name="hibernate.cache.region.factory_class"
          value="org.hibernate.cache.ehcache.EhCacheRegionFactory"/>
        ...
    </properties>
    

    or you can do it in application.properties

    spring.data.jpa.hibernate.cache.use_second_level_cache=true
    spring.data.jpa.hibernate.cache.region.factory_class=org.hibernate.cache.ehcache.EhCacheRegionFactory
    

    3 Add @Cacheable annotation to your entity.

    @Entity
    @Cacheable
    class Category(...){
    .........
    }
    

    That's all for the start. The Category will be read from DB one time and stored in the second level cache. Next time Hibernate will take it from there, without any new "select from".