hibernate二级缓存使用hazelcast实现,集合元素不是从缓存中检索的,而是从数据库中检索的

hibernate二级缓存使用hazelcast实现,集合元素不是从缓存中检索的,而是从数据库中检索的,hibernate,spring-boot,orm,hazelcast,second-level-cache,Hibernate,Spring Boot,Orm,Hazelcast,Second Level Cache,我对二级缓存有一种“奇怪”的行为,它不会从缓存中命中集合的元素,而是从数据库中命中集合的元素 有三个类可以建模用户和组之间具有属性的多个关系 用户和组类从中继承的Person类: @Entity @DiscriminatorColumn(name = "userType", discriminatorType = DiscriminatorType.INTEGER) @Inheritance(strategy = InheritanceType.SINGLE_TABLE) @Cacheable

我对二级缓存有一种“奇怪”的行为,它不会从缓存中命中集合的元素,而是从数据库中命中集合的元素

有三个类可以建模用户和组之间具有属性的多个关系

用户和组类从中继承的Person类:

@Entity
@DiscriminatorColumn(name = "userType", discriminatorType = DiscriminatorType.INTEGER)
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@Cacheable
@org.hibernate.annotations.Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
public class Person implements Serializable {
...
}


@Entity
@DiscriminatorValue("2")
public class User extends Person {

    @OneToMany(mappedBy = "user", cascade = {CascadeType.ALL}, orphanRemoval = true, fetch = FetchType.LAZY)
    @org.hibernate.annotations.Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
    protected Set<UserGroup> userGroups = new HashSet<>();
}


@Entity
@DiscriminatorValue("2")
public class Group extends Person {

    @OneToMany(mappedBy = "group", fetch = FetchType.LAZY, cascade = CascadeType.ALL, orphanRemoval = true)
    @org.hibernate.annotations.Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
    protected Set<UserGroup> users = new HashSet<>();

}
所有实体和集合都配置为可缓存

我做了一个测试,在这个测试中,我从数据库中的一个用户的ID中检索了一个用户,然后我对UserGroup集合进行了一次get,hibernate生成了这个查询,这是因为惰性模式配置的缘故。 我在一个循环中做了好几次

@Test
@Transactional
public void level2QueryCacheSelectTest() {

    for (int i = 0; i < 5; i++) {

        Optional<User> oUser = this.userRepository.findById(1l);

        User user = oUser.get();

        logger.info(user.toString());

        for (UserGroup ug : user.getUserGroups()) {
            logger.info(ug.toString());
        }
    }
}
仅使用用户id检索的用户组,即user.userGroups集合的元素

select
    usergroups0_.id_user as id_user2_6_0_,
    usergroups0_.id_group as id_group1_6_0_,
    ...
from
    user_group usergroups0_ 
where
    usergroups0_.id_user=?
这里是我可以通过Hazelcast mancenter看到的二级缓存中的结果

用户是4个组的成员,因此在oauth2.domain.UserGroup区域中有4个条目,在oauth2.domain.userGroups区域中有1个集合

现在是第二次执行出现问题的测试:)

在测试的第一次迭代中,Hibernate使用用户id和组id对UserGroup表进行4次查询。因此,他可以在缓存中检索集合(因为他已经知道组的id),但不能检索应该位于oauth2.domain.UserGroup区域中的集合元素

    select
        usergroup0_.id_group as id_group1_6_0_,
        usergroup0_.id_user as id_user2_6_0_,
    from
        user_group usergroup0_ 
    where
        usergroup0_.id_group=? 
        and usergroup0_.id_user=?

binding parameter [1] as [BIGINT] - [9]
binding parameter [2] as [BIGINT] - [1]
其他3个用户组也一样

现在缓存中有8个UserGroup元素

我不知道为什么在缓存中找不到元素,我使用嵌入的ID实现了用户组类的hashcode和equals。但是我不确定Hazelcast是如何完成这项工作的,所以可能存在配置错误。如果你知道我如何解决这个问题,欢迎你

版本:

冬眠:5.3.12.1决赛

Hazelcast-hibernate53:1.3.2

Hazelcast:3.12.3

弹簧靴:2.0.0.0版本

这是Hazelcast和jpa的Spring引导配置

spring:
    datasource:
        jdbc-url: jdbc:mysql://mysql-server:3306/oauth2
        username: ********
        password: ********
        initialization-mode: never
    jpa:
        hibernate:
            ddl-auto: update
        properties:
            hibernate:
                cache:
                    #required - turn on L2 cache.
                    use_second_level_cache: true
                    #optional - turn on query cache.
                    use_query_cache: true
                    hazelcast:
                      use_native_client: true
                      native_client_address: hazelcast-member:5701
                      native_client_group: *********
                      native_client_password: *********
                    region:
                      factory_class: com.hazelcast.hibernate.HazelcastCacheRegionFactory
                format_sql: true
                #optional - generate statistics to check if L2/query cache is actually being used.
                generate_statistics: true 

你能显示你的
application.properties | yml
文件吗?@Cepr0当然我加了Hazelcast和jpastange的配置。。。设置似乎是正确的。问题可能出在复杂的实体模式中。或者,原因可能是您在
UserGroup
中实现的
hashCode
不完全正确-当您为“-toMany”关联使用
Set
时,最好使用这个。看看我的-我希望它会有用。我使用的测试方法是junit测试。它抛出了一个LazyInitializationException,所以我在方法级别添加了一个@Transactional注释以使其正常工作。这就是问题的根源,我在我的应用程序中进行了实时测试,在没有注释的情况下,它可以正常工作。在我的集合中,我从不添加任何ID为null的元素,因此我认为这不是问题,我不同意hashcode总是返回相同值的技巧,因为该值用于快速检索、删除或添加元素。(~O(1))。感谢回购协议,我会看一看;)
select
    usergroups0_.id_user as id_user2_6_0_,
    usergroups0_.id_group as id_group1_6_0_,
    ...
from
    user_group usergroups0_ 
where
    usergroups0_.id_user=?
    select
        usergroup0_.id_group as id_group1_6_0_,
        usergroup0_.id_user as id_user2_6_0_,
    from
        user_group usergroup0_ 
    where
        usergroup0_.id_group=? 
        and usergroup0_.id_user=?

binding parameter [1] as [BIGINT] - [9]
binding parameter [2] as [BIGINT] - [1]
spring:
    datasource:
        jdbc-url: jdbc:mysql://mysql-server:3306/oauth2
        username: ********
        password: ********
        initialization-mode: never
    jpa:
        hibernate:
            ddl-auto: update
        properties:
            hibernate:
                cache:
                    #required - turn on L2 cache.
                    use_second_level_cache: true
                    #optional - turn on query cache.
                    use_query_cache: true
                    hazelcast:
                      use_native_client: true
                      native_client_address: hazelcast-member:5701
                      native_client_group: *********
                      native_client_password: *********
                    region:
                      factory_class: com.hazelcast.hibernate.HazelcastCacheRegionFactory
                format_sql: true
                #optional - generate statistics to check if L2/query cache is actually being used.
                generate_statistics: true