为什么 Hibernate with Specification 在第一个查询得到所有要求时进行两次查询?
Why is Hibernate with Specification making two queries when the first one got everything that was asked?
我正在练习Spring启动应用程序。
我有 3 个实体(按建议编辑):
class User extends EntityModelTemplate {
String username; //unique
@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY, mappedBy = "user")
List<UserRoles> userRoles;
}
@IdClass(UserRolesKey.class)
class UserRoles {
@Id
@ManyToOne
@JoinColumn(name = "user_id")
User user;
@Id
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "role_id")
Role role;
}
class Role extends EntityModelTemplate{
String role;
@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY, mappedBy = "role")
List<UserRoles> userRoles;
}
我想做一个 单一 数据库调用,它会获取用户和角色,所以我尝试使用规范。我阅读了文档并在线搜索了示例,然后提出了一些应该像我想要的那样工作的东西。
服务方式(推荐编辑):
public UserDTO getUserForSecurityCheck(String username) throws UsernameNotFoundException {
log.info("Repository call start!");
Optional<User> user = userRepo.findOne(Specification.where(UserSpecifications.usernameEquals(username)));
log.info("Repository call end!");
return user.map(UserDTO::new).orElseThrow(() -> new UsernameNotFoundException("Username "+username+" not found!"));
}
规格:
public static Specification<User> usernameEquals(String username){
return (root, query, criteriaBuilder) -> {
( (Join<Object, Object>) root.fetch(User_.USER_ROLES)).fetch(UserRoles_.ROLE);
return criteriaBuilder.equal(root.get(User_.USERNAME), username);
};
}
除了 Hibernate 进行两次数据库调用外,它工作得很好。
(编辑)
第一个使用两个连接选择所有需要的,其中 username=? (它相当长,因此是短版)。这正是我想要它做的。
但随后它进行了第二次调用,从字面上执行 Select *(userRoles 除外) from user where user_id=?.
为什么?
虽然我在一般编码方面仍然是新手,但我非常确定我了解规范和 Hibernate 的工作原理。至少是基础知识。显然我不知道。
所以,我的问题是:是应该进行两次数据库调用还是我做错了什么?
提前致谢。
我发现了我的错误,我为没有立即注意到它而感到非常尴尬:
默认情况下,UserRoles 中的用户是急切加载的。那是第二个电话。我将其更改为懒惰并且按预期工作。
要不是M.Deinum问一个懒人collection,我一百万年都不会注意到它。
我正在练习Spring启动应用程序。
我有 3 个实体(按建议编辑):
class User extends EntityModelTemplate {
String username; //unique
@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY, mappedBy = "user")
List<UserRoles> userRoles;
}
@IdClass(UserRolesKey.class)
class UserRoles {
@Id
@ManyToOne
@JoinColumn(name = "user_id")
User user;
@Id
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "role_id")
Role role;
}
class Role extends EntityModelTemplate{
String role;
@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY, mappedBy = "role")
List<UserRoles> userRoles;
}
我想做一个 单一 数据库调用,它会获取用户和角色,所以我尝试使用规范。我阅读了文档并在线搜索了示例,然后提出了一些应该像我想要的那样工作的东西。
服务方式(推荐编辑):
public UserDTO getUserForSecurityCheck(String username) throws UsernameNotFoundException {
log.info("Repository call start!");
Optional<User> user = userRepo.findOne(Specification.where(UserSpecifications.usernameEquals(username)));
log.info("Repository call end!");
return user.map(UserDTO::new).orElseThrow(() -> new UsernameNotFoundException("Username "+username+" not found!"));
}
规格:
public static Specification<User> usernameEquals(String username){
return (root, query, criteriaBuilder) -> {
( (Join<Object, Object>) root.fetch(User_.USER_ROLES)).fetch(UserRoles_.ROLE);
return criteriaBuilder.equal(root.get(User_.USERNAME), username);
};
}
除了 Hibernate 进行两次数据库调用外,它工作得很好。
(编辑)
第一个使用两个连接选择所有需要的,其中 username=? (它相当长,因此是短版)。这正是我想要它做的。 但随后它进行了第二次调用,从字面上执行 Select *(userRoles 除外) from user where user_id=?.
为什么?
虽然我在一般编码方面仍然是新手,但我非常确定我了解规范和 Hibernate 的工作原理。至少是基础知识。显然我不知道。
所以,我的问题是:是应该进行两次数据库调用还是我做错了什么?
提前致谢。
我发现了我的错误,我为没有立即注意到它而感到非常尴尬: 默认情况下,UserRoles 中的用户是急切加载的。那是第二个电话。我将其更改为懒惰并且按预期工作。
要不是M.Deinum问一个懒人collection,我一百万年都不会注意到它。