我在Google上搜索了很多东西,而Spring Boot(最新版本)可能没有延迟加载的确很奇怪。以下是我的代码片段:
我的资源
: public ResponseEntity<Page<AirWaybill>> searchAirWaybill(CriteraDto criteriaDto, @PageableDefault(size = 10) Pageable pageable{
airWaybillService.searchAirWaybill(criteriaDto, pageable);
return ResponseEntity.ok().body(result);
}
我的服务
@Service
@Transactional
public class AirWaybillService {
//Methods
public Page<AirWaybill> searchAirWaybill(AirWaybillCriteriaDto searchCriteria, Pageable pageable){
//Construct the specification
return airWaybillRepository.findAll(spec, pageable);
}
}
我的实体:
@Entity
@Table(name = "TRACKING_AIR_WAYBILL")
@JsonIdentityInfo(generator=ObjectIdGenerators.IntSequenceGenerator.class, property="@airWaybillId") //to fix Infinite recursion with LoadedAirWaybill class
public class AirWaybill{
//Some attributes
@NotNull
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "FK_TRACKING_CORPORATE_BRANCH_ID")
private CorporateBranch corporateBranch;
}
在调试时,我仍然将所有延迟加载的属性加载。参见下图。
我的问题之一是杰克逊会参与这种行为吗? 我可能错过了激活延迟加载的任何方式吗?
编辑
另一个问题,调试器是否可以破坏延迟加载?
编辑2:
对于规格版本,我有:
public static Specification<AirWaybill> isBranchAirWayBill(long id){
return new Specification<AirWaybill>() {
@Override
public Predicate toPredicate(Root<AirWaybill> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
return cb.equal(root.join("corporateBranch",JoinType.LEFT).get("id"),id);
}
};
}
答案 0 :(得分:3)
默认情况下,SpringBoot已启用:
spring.jpa.open-in-view = true
这意味着交易始终是开放的。尝试禁用它。
更多信息here
答案 1 :(得分:1)
使用调试器时,您尝试访问变量的值。因此,当您单击屏幕上的那个小箭头时,有问题的变量的值会(延迟)加载。
答案 2 :(得分:1)
很可能您仍在服务内部进行调试,因此在事务仍处于活动状态并且可以触发延迟加载(在延迟元素上调用的任何方法都会触发从数据库中的提取)。
问题在于,在事务之外无法进行延迟加载。杰克逊绝对在解析您的实体。
构建规范时,您应该获取所有必需的依赖项,或者在资源级别上尝试使用@Transactional
(但请尽量尝试)。
就像您知道的那样,LAZY的获取策略只是一个提示。.不是强制性操作。渴望是必须的:
LAZY策略是对持久性提供程序运行时的提示, 首次访问时应延迟获取数据。的 允许实现急于获取LAZY的数据 策略提示已指定。
答案 3 :(得分:1)
只是一个猜测:您在建立规范时要强制进行提取。
我希望类似
static Specification<AirWaybill> buildSpec() {
return (root, query, criteriaBuilder) -> {
Join<AirWaybill, CorporateBranch> br = (Join) root.fetch("corporateBranch");
return criteriaBuilder.equal(br.get("addressType"), 1);
};
}
在这种情况下,请尝试将root.fetch
更改为root.join
答案 4 :(得分:1)
休眠会话存在于带有@Transactional
的方法中。
在Service类之外传递实体是一种不好的做法,因为在离开您的search
方法之后,会话正在关闭。另一方面,您的实体包含惰性的初始化集合,一旦会话关闭,就无法提取它们。
好的做法是将实体映射到传输对象上,然后从服务(不是原始实体)中返回那些传输对象。
答案 5 :(得分:0)
您可以使用jackson-datatype-hibernate的2个步骤解决此问题:
kotlin示例
build.gradle.kts
:implementation("com.fasterxml.jackson.datatype:jackson-datatype-hibernate5:$jacksonHibernate")
@Bean
@Bean
fun hibernate5Module(): Module = Hibernate5Module()
请注意,Module
是com.fasterxml.jackson.databind.Module
,而不是java.util.Module
答案 6 :(得分:0)
另一个考虑是在使用 Lombok 时,@Data/@Getter 注释导致不需要加载惰性项。所以在使用 Lombok 时要小心。
这是我的情况。
答案 7 :(得分:-1)
检索到的数据已经很懒了,但是当您单击以查看调试器中的数据时,您正在使用调试模式下的返回值。
答案 8 :(得分:-1)
我也面临着弹簧数据JPA同样的问题。我加了注解如下:能够得到客户记录指定订单ID
客户到订单:一对多
给客户的订单是延迟加载。
<强> Order.java 强>
#!/bin/bash
yum update -y
yum install -y httpd.x86_64
systemctl start httpd.service
systemctl enable httpd.service
echo “Hello World from $(hostname -f)” > /var/www/html/index.html
<强> Customer.java 强>
@ManyToOne(cascade = CascadeType.ALL,targetEntity = CustomerEntity.class,fetch = FetchType.LAZY)
@Fetch(FetchMode. JOIN)
@JoinColumn(name = "CUSTOMER_ID",referencedColumnName = "CUSTOMER_ID",insertable = false,updatable = false)
@LazyToOne(LazyToOneOption.PROXY)
Private CustomerEntity customer