java - 为什么 Hibernate with Specification 在第一个得到所有被询问的内容时会进行两个查询?
问题描述
我正在做一个练习 Spring Boot 应用程序。
我有 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 进行两次数据库调用外,它工作得很好。
(编辑)
第一个使用两个连接选择所有需要的用户名=?(它相当长,因此是简短的版本)。这正是我想要它做的。但随后它进行了第二次调用,该调用实际上是从 user_id=? 的用户中选择 *(userRoles 除外)。
为什么?
尽管我在一般情况下仍然是编码新手,但我很确定我了解规范和 Hibernate 是如何工作的。至少是基本的。显然我没有。
所以,我的问题是:假设要进行两次数据库调用还是我做错了什么?
提前致谢。
解决方案
我发现了自己的错误,并且因为没有立即注意到它而感到非常尴尬:默认情况下,UserRoles 中的用户被急切地加载。那是第二个电话。我把它改成了懒惰的,它按预期工作。
如果不是 M.Deinum 询问一个惰性集合,我一百万年都不会注意到它。
推荐阅读
- java - 为什么 ResultSet 不从 MySQL 返回数据
- git - 在 AS/400 上安装 GIT
- clojure - clojurecademy,线程宏挑战
- android - 无法从接收器停止 MediaPlayer
- java - 如何通过资源使用格式字符串和 SQL 查询
- ruby-on-rails - 为什么使用连接和包含与 find_each 会导致不正确的迭代计数
- google-apps-script - 谷歌应用脚本:如何保存活动电子表格?
- css - Eclipse 4 用户界面慢。CSS 引擎调用过于频繁 (Windows)
- javascript - URL 字符串的正则表达式模式
- forms - django 表单上传文件返回错误,因为表单无效