JPA延迟加载在Spring Boot中不起作用

时间:2019-04-16 07:19:17

标签: java spring hibernate spring-boot spring-data-jpa

我在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;
}

在调试时,我仍然将所有延迟加载的属性加载。参见下图。

enter image description here

我的问题之一是杰克逊会参与这种行为吗? 我可能错过了激活延迟加载的任何方式吗?

编辑

另一个问题,调试器是否可以破坏延迟加载?

编辑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);
        }
    };
}

9 个答案:

答案 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示例

  1. 添加build.gradle.kts
implementation("com.fasterxml.jackson.datatype:jackson-datatype-hibernate5:$jacksonHibernate")
  1. 创建@Bean
   @Bean
   fun hibernate5Module(): Module = Hibernate5Module()

请注意,Modulecom.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