Java 为什么Hibernate和规范会在第一个查询得到所有要求时进行两次查询?
我正在做一个练习Spring引导应用程序 我有3个实体(按建议编辑):Java 为什么Hibernate和规范会在第一个查询得到所有要求时进行两次查询?,java,spring-boot,hibernate-criteria,Java,Spring Boot,Hibernate Criteria,我正在做一个练习Spring引导应用程序 我有3个实体(按建议编辑): 类用户扩展EntityModelTemplate{ 字符串用户名;//唯一 @OneToMany(cascade=CascadeType.ALL,fetch=FetchType.LAZY,mappedBy=“user”) 列出用户角色; } @IdClass(UserRolesKey.class) 类用户角色{ @身份证 @许多酮 @JoinColumn(name=“user\u id”) 用户; @身份证 @manyton
类用户扩展EntityModelTemplate{
字符串用户名;//唯一
@OneToMany(cascade=CascadeType.ALL,fetch=FetchType.LAZY,mappedBy=“user”)
列出用户角色;
}
@IdClass(UserRolesKey.class)
类用户角色{
@身份证
@许多酮
@JoinColumn(name=“user\u id”)
用户;
@身份证
@manytone(fetch=FetchType.LAZY)
@JoinColumn(name=“role\u id”)
角色;
}
类角色扩展EntityModelTemplate{
字符串角色;
@OneToMany(cascade=CascadeType.ALL,fetch=FetchType.LAZY,mappedBy=“role”)
列出用户角色;
}
我想做一个单个DB调用,它将获取用户和角色,所以我尝试使用规范。我阅读了文档并在网上搜索了一些例子,然后想出了一些我想要的东西
维修方法(按建议编辑):
public UserDTO getUserForSecurityCheck(字符串username)抛出UsernameNotFoundException{
log.info(“存储库调用启动!”);
可选user=userRepo.findOne(Specification.where(UserSpecifications.usernamequals(username));
log.info(“存储库调用结束!”);
返回user.map(UserDTO::new).orelsetrow(()->newusernameNotFoundException(“Username”+Username+“NotFound!”));
}
规格:
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);
};
}
公共静态规范usernamequals(字符串用户名){
返回(根、查询、准则生成器)->{
((Join)root.fetch(用户角色)).fetch(用户角色角色);
返回criteriaBuilder.equal(root.get(USERNAME)、USERNAME);
};
}
除了Hibernate进行两次DB调用外,它工作得非常好
(编辑)
第一个连接使用两个连接选择所需的所有内容,其中username=?(它相当长,因此是短的,短的版本)。这正是我想要它做的。
但随后它会进行第二次调用,从user_id=
为什么?
尽管我还是一个编码方面的新手,但我很确定我了解规范和Hibernate是如何工作的。至少是基础知识。显然我没有
所以,我的问题是:它应该打两个DB电话,还是我做错了什么
提前谢谢。我发现了我的错误,我很不好意思没有马上注意到: 默认情况下,用户角色中的用户被急切地加载。这是第二个电话。我把它改成了lazy,它按预期工作
如果不是M.Deinum询问一个懒散的收藏,我在一百万年内都不会注意到它。我发现了我的错误,我很不好意思没有立即注意到它: 默认情况下,用户角色中的用户被急切地加载。这是第二个电话。我把它改成了lazy,它按预期工作
如果不是M.Deinum询问一个懒惰的集合,我在一百万年内都不会注意到它。请添加适当的实体(带有映射信息)。看起来您有一种复杂的方式来表达
@manytomy
。您的角色
实体也有一个惰性集合,您并不急于加载它。这可能是由于UserDTO
构造函数中的某些内容触发的。另一方面,不要使用ifPresent
,而是使用user.map(UserDTO::new).orelsetrow(新用户名notfoundexception(“Username”+Username+“notfound!”)代码>@M.Deinum谢谢您抽出时间。我已经按照您的要求添加了适当的实体映射,并按照您的建议更改了服务方法(感谢您的提示!)。角色实体有一个惰性集合,因为每次我需要向新用户添加角色时,加载整个UserRoles列表似乎不太好。我很确定我已经读过,延迟加载不能在存储库之外完成,这应该排除UserDTO构造函数。请添加适当的实体(带有映射信息)。看起来您有一种复杂的方式来表达@manytomy
。您的角色
实体也有一个惰性集合,您并不急于加载它。这可能是由于UserDTO
构造函数中的某些内容触发的。另一方面,不要使用ifPresent
,而是使用user.map(UserDTO::new).orelsetrow(新用户名notfoundexception(“Username”+Username+“notfound!”)代码>@M.Deinum谢谢您抽出时间。我已经按照您的要求添加了适当的实体映射,并按照您的建议更改了服务方法(感谢您的提示!)。角色实体有一个惰性集合,因为每次我需要向新用户添加角色时,加载整个UserRoles列表似乎不太好。我很确定我已经读过,延迟加载不能在存储库之外完成,这应该排除UserDTO构造函数。
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);
};
}