所以這裏是我的情況:我想用Jackson和Hibernate構建一個簡單的CRUD webservice。看起來像是Spring Boot的完美工作。因此,我們有以下幾點:傑克遜+休眠=很多問題
(請注意,我冷凝的代碼,所以它不是編譯能)
class Doctor {
@Id
long id;
@ManyToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
@JoinTable(name = "doctor_service", joinColumns = { @JoinColumn(name = "doctor_id", nullable = false) }, inverseJoinColumns = { @JoinColumn(name = "service_id", nullable = false) })
Set<Service> services;
}
class Service {
@Id
long id;
@ManyToMany(fetch = FetchType.EAGER, mappedBy = "services")
Set<Doctor> doctors;
}
一個簡單的數據模型。我們有一個簡單的要求:在web服務上,當我們獲得Service對象時,我們應該得到相關的Doctors。當我們得到醫生時,我們應該得到相關的服務。我們正在使用懶惰,因爲[在這裏插入理由]。
所以,現在讓爲它服務:
@Path("/list")
@POST
@Produces(MediaType.APPLICATION_JSON)
@Transactional
public JsonResponse<List<Doctor>> list() {
return JsonResponse.success(doctorCrudRepo.findAll());
}
粉飾JsonResponse對象(只是一個方便的黑箱現在),讓承擔doctorCrudRepo是CrudRepository的有效實例。
而風暴開始:
failed to lazily initialize a collection of role: Doctor.services, could not initialize proxy - no Session (through reference chain: ...)
好了,所以懶惰不工作呢。夠簡單。只是讓它渴望。
Caused by: java.lang.StackOverflowError: null
at java.lang.ClassLoader.defineClass1(Native Method)
at java.lang.ClassLoader.defineClass(ClassLoader.java:760)
at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:142)
at java.net.URLClassLoader.defineClass(URLClassLoader.java:455)
at java.net.URLClassLoader.access$100(URLClassLoader.java:73)
at java.net.URLClassLoader$1.run(URLClassLoader.java:367)
at java.net.URLClassLoader$1.run(URLClassLoader.java:361)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:360)
at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:308)
at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
at com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:655)
... 1011 common frames omitted
所以讓我們看看其他人紛紛表示:
Contestant #1:解決方案是不相關的,因爲它們適用於一到多,沒有多到很多,所以我仍然得到的StackOverflowError。
Contestant #2:和以前一樣,仍然是一對多的,仍然是StackOverflow。
Contestant #3:同(已經沒有人使用了許多一對多???)
Contestant #4:因爲這意味着它會永遠被連載我不能使用@JsonIgnore。所以它不符合要求。
Contestant #5:乍一看,它似乎工作正常!但是,只有博士端點才能工作 - 它正在獲得服務。服務端點不起作用 - 它沒有得到醫生(空集)。它可能基於哪個引用定義了連接表。這又不符合法案。
Contestant #6:沒有。
一些其他的解決方案,是錯誤的,但值得一提:
創建一個新的組中不被休眠包裹的JSON序列化對象,然後在控制器複製的屬性。這是很多額外的工作。任何地方強制使用這種模式都會影響使用Hibernate的目的。
加載Doctor後,循環遍歷每個Service並將service.doctors設置爲null,以防止進一步的延遲加載。我正在嘗試建立一套最佳實踐,而不是提出駭人的解決方法。
因此......RIGHT解決方案是什麼?我可以遵循什麼樣的模式,看起來很乾淨,讓我爲使用Hibernate和Jackson感到驕傲?還是這種技術的組合如此矛盾以至於無法提出新的範式?
你試過Hibernate.initialize(service.getDoctors())嗎? –
是的。這是參賽者#1提出的解決方案之一。但是每個醫生都會再次提到服務,所以我得到了一個稍微不同的錯誤信息,但有着相同的根本原因。 –
發佈實體的實際代碼,而不是它的某些派生部分。一般來說,如果你不休眠可能會感到困惑,你必須指定'mappedBy'。你也提到堆棧溢出,請添加堆棧跟蹤以查看它出錯的地方。理論上,當你正確地進行了設置時,急切的加載應該可行,我懷疑你的'@ Transactional'幾乎沒用,因爲它是一個JAX-RS而不是一個spring bean。 –