[英]JPA Lazy loading is not working in Spring boot
我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;
}
而且在調試時,我仍然會加載所有延遲加載的屬性。 見下圖。
我的問題之一是 Jackson 會參與這種行為嗎? 有什么我可能錯過的激活延遲加載的方法嗎?
編輯
另一個問題,調試器是否會參與破壞延遲加載?
編輯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);
}
};
}
Hibernate Session 存在於帶有@Transactional
方法中。 在 Service 類之外傳遞實體是一種不好的做法,因為在離開您的search
方法后會話將被關閉。 另一方面,您的實體包含延遲初始化的集合,一旦會話關閉就無法拉出。
好的做法是將實體映射到傳輸對象並從服務中返回這些傳輸對象(而不是原始實體)。
很可能您仍在服務內部進行調試,因此當事務仍然處於活動狀態時,可以觸發延遲加載(在延遲元素上調用的任何方法都會觸發從數據庫中獲取)。
問題是在事務之外時不能發生延遲加載。 傑克遜正在解析您的實體,絕對超出了實體的邊界。
您應該在構建規范時獲取所有必需的依賴項,或者在資源級別嘗試使用@Transactional
(但作為最后的手段嘗試)。
只是為了讓您知道,LAZY 獲取策略只是一個提示.. 不是強制性操作。 渴望是強制性的:
LAZY 策略是對持久性提供程序運行時的一個提示,即在第一次訪問數據時應該延遲獲取數據。 允許實現急切地獲取已為其指定 LAZY 策略提示的數據。
SpringBoot 默認已啟用:
spring.jpa.open-in-view = true
這意味着交易始終是開放的。 嘗試禁用它。
更多信息在這里
使用調試器時,您正在嘗試訪問變量的值。 因此,當您單擊屏幕上的那個小箭頭時,相關變量的值就被(延遲地)加載了。
只是猜測:您在構建規范時強制獲取。
我希望像
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
檢索到的數據已經延遲,但您正在使用調試模式,當單擊從調試器查看數據時,它的返回值。
你可以用jackson-datatype-hibernate用 2 個步驟來解決這個問題:
科特林示例
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
另一個考慮是在使用 Lombok 時,@Data/@Getter 注釋會導致不需要加載惰性項。 所以在使用 Lombok 時要小心。
這是我的情況。
我想您正在使用 Hibernate 作為 JPA。
從規格:
EAGER 策略是對持久性提供程序運行時的要求,即必須急切地獲取數據。 LAZY 策略是對持久性提供程序運行時的提示,即在首次訪問數據時應該延遲獲取數據。 允許該實現急切地獲取已指定 LAZY 策略提示的數據。 https://docs.jboss.org/hibernate/jpa/2.2/api/javax/persistence/FetchType.html
Hibernate 在非擁有方的 OneToOne 和 ManyToOne 關系中特別忽略 fetch 類型。
如果你真的需要它,如何強制 Hibernate 使用獲取類型 LAZY 的選項很少。
有關更多信息,請查看: http://justonjava.blogspot.com/2010/09/lazy-one-to-one-and-one-to-many.html
我想我可能有一個解決方案。 你可以試試這個。 經過 4 小時的打擊和試用后,這對我有用-
用戶實體:
class User {
@Id
String id;
@JsonManagedReference
@OneToMany(mappedBy = "user", fetch = FetchType.LAZY)
private List<Address> addressDetailVOList = new ArrayList<Address>();
}
地址實體:
class Address {
@JsonBackReference
@ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name = "userId")
private User user;
}
您的父 class 將使用 @JsonManagedReference,子 class 將使用 @JsonBackReference。 這樣,您可以避免實體對象的無限循環作為響應和堆棧溢出錯誤。
我也遇到了與 Spring 數據 JPA 相同的問題。 我添加了以下注釋並能夠獲取給定 ORDER ID 的客戶記錄
客戶訂購:一對多
給客戶的訂單是延遲加載。
訂單.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
客戶.java
@Entity
@TabLe(name = "CUSTOMER" ,
uniqueConstraints = @UniqueConstraint(columnNames= {"mobile"}))
public class CustomerEntity {
@GeneratedVaLue(strategy = GenerationType.IDENTITY)
@CoLumn(name = "customer_id" )
private Integer customerld;
private String name;
private String address;
private String city;
private String state;
private Integer zipCode;
private Integer mobileNumber;
@OneToMany(mappedBy = " customer" )
@Fetch(FetchMode.JOIN)
@LazyToOne(LazyToOneOption.PROXY)
private List<OrderEntity> orders;
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.