Hibernate二级缓存使用与jpa问题

问题描述 投票:0回答:1

我想重新创建的案例:

  1. 应用程序启动并将一张表从 postgres DB 放入缓存
  2. 对该表的所有查询都必须执行并使用二级缓存而不是数据库连接。

构建.gradle:

dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
    implementation 'org.hibernate.orm:hibernate-jcache:6.1.6.Final'
    implementation 'org.springframework.boot:spring-boot-starter-web'
    runtimeOnly 'org.postgresql:postgresql'
    testImplementation 'org.springframework.boot:spring-boot-starter-test'
    implementation 'org.ehcache:ehcache:3.10.8'
}

应用程序属性:

spring.jpa.show-sql=true
spring.jpa.properties.javax.persistence.sharedCache.mode=ENABLE_SELECTIVE
spring.jpa.properties.hibernate.format_sql=true
spring.jpa.properties.hibernate.generate_statistics=true
spring.jpa.properties.hibernate.cache.use_second_level_cache=true
spring.jpa.properties.hibernate.cache.use_query_cache=true
spring.jpa.properties.hibernate.cache.region.factory_class= 
org.hibernate.cache.jcache.JCacheRegionFactory
spring.jpa.hibernate.ddl-auto=none

缓存初始化:

@Configuration
public class CacheConfig {

    private final RegionsRepo repo;

    public CacheConfig(RegionsRepo repo) {
        this.repo = repo;
    }

    @PostConstruct
    public void initCache() {
        repo.findAll().forEach(region -> {});
    }
}

实体注释:

@Entity
@Cacheable
@org.hibernate.annotations.Cache(usage = CacheConcurrencyStrategy.READ_ONLY) 
@Table(name = "regions")

和 JpaRepository:

public interface RegionsRepo extends JpaRepository<Regions, Long> {
    
    Optional<Regions> findRegionsByExternalid(Integer id);

    @Override
    Optional<Regions> findById(Long aLong);

    @Override
    @QueryHints(@QueryHint(name = org.hibernate.annotations.QueryHints.CACHEABLE, value = "true"))
    List<Regions> findAll();
}

启动应用程序后,将表放入二级休眠缓存中。日志:

 346333 nanoseconds spent acquiring 1 JDBC connections;
    0 nanoseconds spent releasing 0 JDBC connections;
    73250 nanoseconds spent preparing 1 JDBC statements;
    1098084 nanoseconds spent executing 1 JDBC statements;
    0 nanoseconds spent executing 0 JDBC batches;
    5962251 nanoseconds spent performing 3 L2C puts;
    0 nanoseconds spent performing 0 L2C hits;
    368667 nanoseconds spent performing 1 L2C misses;
    0 nanoseconds spent executing 0 flushes (flushing a total of 0 entities and 0 collections);
    68458 nanoseconds spent executing 1 partial-flushes (flushing a total of 0 entities and 0 collections)

当我调用存储库方法时

按 ID 查找

这是从 JpaRepository 重写的,我看到没有执行 JDBC 语句,只是纯粹的 L2C 命中,这正是我所需要的。 日志:

    1277291 nanoseconds spent acquiring 1 JDBC connections;
    0 nanoseconds spent releasing 0 JDBC connections;
    0 nanoseconds spent preparing 0 JDBC statements;
    0 nanoseconds spent executing 0 JDBC statements;
    0 nanoseconds spent executing 0 JDBC batches;
    0 nanoseconds spent performing 0 L2C puts;
    418709 nanoseconds spent performing 1 L2C hits;
    0 nanoseconds spent performing 0 L2C misses;
    0 nanoseconds spent executing 0 flushes (flushing a total of 0 entities and 0 collections);
    0 nanoseconds spent executing 0 partial-flushes (flushing a total of 0 entities and 0 collections)

但是当我使用自定义的而不是重写的方法时

通过外部 ID 查找区域

L2C 命中被忽略。日志:

742083 nanoseconds spent acquiring 1 JDBC connections;
0 nanoseconds spent releasing 0 JDBC connections;
849083 nanoseconds spent preparing 1 JDBC statements;
2029042 nanoseconds spent executing 1 JDBC statements;
0 nanoseconds spent executing 0 JDBC batches;
670583 nanoseconds spent performing 1 L2C puts;
0 nanoseconds spent performing 0 L2C hits;
0 nanoseconds spent performing 0 L2C misses;
0 nanoseconds spent executing 0 flushes (flushing a total of 0 entities and 0 collections);
0 nanoseconds spent executing 0 partial-flushes (flushing a total of 0 entities and 0 collections)

您能告诉一下这种情况下 hibernate 缓存配置有什么问题吗?

我应该怎么做才能让 hibernate 在非重写的 JpaRepository 方法中使用 L2C 缓存?

java spring hibernate jpa
1个回答
0
投票

最终自己解决了。

由于 hibernate-jache 默认提供程序可以通过作为主键的实体 id 进行搜索,因此我只是在数据库中重新创建没有 id 的实体。

之前签名:

@Id
@GeneratedValue(strategy = GenerationType.AUTO)
Long id;
Integer externalid;
String externalname;
Integer internalid;
String internalname;

这里我们只需使用Long id字段就可以在L2C上进行扫描和搜索。

至:

@Id
@GeneratedValue(strategy = GenerationType.TABLE)
Integer externalid;
String externalname;
Integer internalid;
String internalname;

现在 Long id kind og 等于 externalid,我可以在 L2C 缓存中通过它进行搜索。

© www.soinside.com 2019 - 2024. All rights reserved.