hibernate - 具有hazelcast实现的hibernate二级缓存,集合元素不是从缓存中检索而是从数据库中检索
问题描述
我对二级缓存有一个“奇怪”的行为,它不会从缓存中命中集合的元素,而是从数据库中命中。
有三个类可以用用户和组之间的属性来建模多对多关系。
User 和 Group 类继承的 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<>();
}
使用附加属性映射中间表的 userGroup 类
@Entity
@Cacheable
@org.hibernate.annotations.Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
@NoArgsConstructor
public class UserGroup implements Serializable, Ientity<PkUserGroup> {
@EmbeddedId
@NotNull
private PkUserGroup id;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "idUser", referencedColumnName = "id", insertable = false, updatable = false)
@org.hibernate.annotations.Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
private User user;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "idGroup", referencedColumnName = "id", insertable = false, updatable = false)
@org.hibernate.annotations.Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
private Group group;
...
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
UserGroup userGroup = (UserGroup) o;
return id.equals(userGroup.id);
}
@Override
public int hashCode() {
return Objects.hash(id);
}
}
UserGroup 类 ID 的可嵌入键
@Embeddable
@NoArgsConstructor
@AllArgsConstructor
@Getter
@Setter
@EqualsAndHashCode
@ToString
public class PkUserGroup implements Serializable {
private Long idUser;
private Long idGroup;
}
所有实体和集合都配置为可缓存。
我做了一个测试,从他的 ID 中检索数据库中的用户,然后我对 UserGroup 集合进行了获取,并且由于 Lazy 模式配置,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());
}
}
}
Hibernate 在第一次迭代时按预期生成两个选择,然后它使用第一级缓存并打印相同的结果。
用户请求:
select
user0_.id as id2_1_0_,
user0_.name as name7_1_0_,
...
from
users user0_
where
user0_.id=?
and user0_.user_type=1
仅使用用户的 id 检索到的 userGroups,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 个用户组元素
我不确定为什么在缓存中找不到元素,我使用嵌入式 ID 实现了 UserGroup 类的 hashcode 和 equals。但我不确定 Hazelcast 是如何完成这项工作的,所以可能存在配置错误。如果您有任何想法我该如何解决该问题,欢迎您。
版本:
休眠:5.3.12.Final
Hazelcast-hibernate53:1.3.2
榛树:3.12.3
春季启动:2.0.0.RELEASE
这是 Hazelcast 和 jpa 的 Spring-boot 配置。
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
解决方案
推荐阅读
- django - 无法找出 Django 中的 NoReverseMatch 错误
- mysql - 无法使用命令行安装craft3。测试数据库凭据...失败:
- sql - 查找 Nuget 包文档
- asp.net-mvc - 在 ASP.NET CORE APPLICATION 中将请求从 GET 转换为 POST
- sql - 从字段中获取价值
- php - 如何根据 PHP 中的匹配值推送值
- amazon-web-services - 断开连接:filezilla 中没有可用的受支持的身份验证方法(服务器发送:公钥)
- c# - 使用 c#/php/anylanguage 检测纸上的签名点
- wordpress - 产品列为“允许延期交货”但显示为“有货”
- python - 如何总结列的多个平均值?