JPA一對多迴圈引用的解決

来源:http://www.cnblogs.com/zr520/archive/2016/04/06/5357459.html
-Advertisement-
Play Games

說是解決,其實不是很完美的解決的,寫出來只是想記錄一下這個問題或者看一下有沒有哪位仁兄會的,能否知道一二。 下麵說說出現問題: 問題是這樣的,當我查詢一個一對多的實體的時候,工具直接就爆了,差不多我就猜到是哪裡死迴圈了,最後等了好久,查看原因,果然是堆溢出,再然後是jsckson的錯誤。那麼必然是序 ...


說是解決,其實不是很完美的解決的,寫出來只是想記錄一下這個問題或者看一下有沒有哪位仁兄會的,能否知道一二。

下麵說說出現問題:

問題是這樣的,當我查詢一個一對多的實體的時候,工具直接就爆了,差不多我就猜到是哪裡死迴圈了,最後等了好久,查看原因,果然是堆溢出,再然後是jsckson的錯誤。那麼必然是序列化的問題了。

這是jackson的錯誤:

at java.security.AccessController.doPrivileged(Native Method)
    at java.net.URLClassLoader.findClass(URLClassLoader.java:354)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:425)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:412)
    at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:308)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:358)
    at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1617)
    at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1547)
    at com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:691)
    at com.fasterxml.jackson.databind.ser.BeanSerializer.serialize(BeanSerializer.java:157)
    at com.fasterxml.jackson.databind.ser.BeanPropertyWriter.serializeAsField(BeanPropertyWriter.java:656)
    at com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:675)
    at com.fasterxml.jackson.databind.ser.BeanSerializer.serialize(BeanSerializer.java:157)

這是迴圈引用的錯誤:

嚴重: Servlet.service() for servlet [springDispatcherServlet] in context with path [/Shop] threw exception [Request processing failed; nested exception is org.springframework.http.converter.HttpMessageNotWritableException: Could not write JSON: Infinite recursion (StackOverflowError) (through reference chain: com.web.module.index.model.entity.Account["user"]->com.web.module.index.model.entity.User["accounts"]->org.hibernate.collection.internal.PersistentSet[0]->com.web.module.index.model.entity.Account["user"]->com.web.module.index.model.entity.User["accounts"]->org.hibernate.collection.internal.PersistentSet[0]->com.web.module.index.model.entity.Account["user"]->com.web.module.index.model.entity.User["accounts"]->org.hibernate.collection.internal.PersistentSet[0]->com.web.module.index.model.entity.Account["user"]->com.web.module.index.model.entity.User["accounts"]->org.hibernate.collection.internal.PersistentSet[0]->com.web.module.index.model.entity.Account["user"]->com.web.module.index.model.entity.User["accounts"]->org.hibernate.collection.internal.PersistentSet[0]->com.web.module.index.model.entity.Account["user"]->com.web.module.index.model.entity.User["accounts"]->org.hibernate.collection.internal.PersistentSet[0]->com.web.module.index.model.entity.Account["user"]->com.web.module.index.model.entity.User["accounts"]->org.hibernate.collection.internal.PersistentSet[0]-
j。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。還有很多的相同的錯誤

下麵是兩個實體:

User.java:

package com.web.module.index.model.entity;

import java.io.Serializable;
import java.util.HashSet;
import java.util.Set;

import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;

import org.hibernate.validator.constraints.NotEmpty;

import com.fasterxml.jackson.annotation.JsonIgnore;

@XmlAccessorType(XmlAccessType.FIELD)
@XmlRootElement(name="user")
@Entity
public class User implements Serializable{
    
    /**
     * 
     */
    private static final long serialVersionUID = 1L;
    @XmlElement
    @Id
    private String id;
    /**
     * validate適用於springmvc
     */
    @XmlElement
    //@NotEmpty
    private String name;
    
    @JsonIgnore
    @OneToMany(mappedBy="user",targetEntity=Account.class,fetch=FetchType.EAGER)
    private Set<Account> accounts=new HashSet<Account>();

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    
    public Set<Account> getAccounts() {
        return accounts;
    }

    public void setAccounts(Set<Account> accounts) {
        this.accounts = accounts;
    }

    @Override
    public String toString() {
        return "User [id=" + id + ", name=" + name + ", accounts=" + accounts
                + "]";
    }
    
}

Account.java:

package com.web.module.index.model.entity;

import java.io.Serializable;

import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;

import com.fasterxml.jackson.annotation.JsonIgnore;

@Entity
public class Account implements Serializable{

    /**
     * 
     */
    private static final long serialVersionUID = 1L;
    
    @Id
    private String id;
    
    private String code;
    private String password;
    
    @JsonIgnore
    @JoinColumn(name="user_id")
    @ManyToOne(targetEntity=User.class,fetch=FetchType.EAGER)
    private User user;
    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getCode() {
        return code;
    }

    public void setCode(String code) {
        this.code = code;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public User getUser() {
        return user;
    }

    public void setUser(User user) {
        this.user = user;
    }

    @Override
    public String toString() {
        return "Account [id=" + id + ", code=" + code + ", password="
                + password + ", user=" + user + "]";
    }
    
}

 

後來去網上看了一下,這個問題很多人遇到。解決方案也有很多.

1.在關聯的實體上面設置@JsonIgnore,這個註解的意思是表示在序列化的時候,忽略這個屬性.但是我現在的邏輯是在頁面中必須使用到這個關聯實體中的屬性,所以就不能這麼做了,不然在頁面中是取不出這個數據的。

Uncaught TypeError: Cannot read property 'name' of undefined(1,2都會出現)

2.採用單向多對一的形式,這樣就不會出現迴圈的問題,這個確實是個方案,但是如果在一的那邊需要使用到多的這邊的話,就不好搞了。所以感覺還是不是很滿意。

3.後來想了想,既然是這樣,要不我在一的那邊使用@JsonIgnore吧。目前在頁面中沒使用。其實這個是第二個是差不多的,有點不同的是除了頁面展示的時候不能夠顯示多的那面的數據,在其他的業務中還是能夠使用的。這也是我在前面說不是很滿意的解決辦法。

4.第四種解決就是前面的3差不多,當我們使用多的一邊的時候,可以正確的顯示,但是在我們使用一的那一端的時候,我們可以使用List自己拼裝,有點像下麵的代碼:

@RequestMapping(value="result/{id}",method=RequestMethod.GET)
    public @ResponseBody List<?> result(@PathVariable("id") String id){
        System.out.println(id);
        List<Map<String,Object>> list=Lists.newArrayList();
        //Map<String,Object> map=new HashMap<String,Object>();
        Map<String,Object> map=null;
        Random r=new Random();
        DecimalFormat dfmt=new DecimalFormat("#,###.00");
        for(int i=0;i<4;i++){
            int price=r.nextInt(10)+1;
            int number=r.nextInt(100000)+10000;
            map=new HashMap<String,Object>();
            map.put("tradegoods", "煤"+i);
            map.put("units", "頓");
            map.put("consumer", "XX物流"+id);
            map.put("unitPrice", dfmt.format(price));
            map.put("number", dfmt.format(number));
            map.put("count", dfmt.format(price*number));
            list.add(map);
        }
        //設置日期格式  
        return list;
    }

這樣jackson序列化的時候,就不會出錯了,而且使用起來就不用像A.B.name這樣了,而且使用起來也更加的簡單。我們在JS裡面就可以這樣使用:

if(id!=""&&id){
            $.ajax({
                type: 'GET',
                url: $ctx + '/example/demo/result/'+id,
                dataType: 'json',
                success: function(data) {
                    for(var i=0;i<data.length;i++){
                        data[i].num=i+1;
                    }
                    //alert(JSON.stringify(data));
                    viewModel.result(data);
                    $(".notice-hide").show();
                    $(".notice-show").hide();
                },
                error: function(req, textStatus, errorThrown){
                }
            });

html:

                <tbody data-bind="foreach: result">
                <tr>
                    <td data-bind="text:num"></td>
                    <td data-bind="text:tradegoods"></td>
                    <td data-bind="text:units"></td>
                    <td data-bind="text:consumer"></td>
                    <td data-bind="text:unitPrice" class="format_"></td>
                    <td data-bind="text:number" class="format_"></td>
                    <td data-bind="text:count" class="format_"></td>
                </tr>
            </tbody>

這樣就完美的解決了這個問題。

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • run: ...
  • 類的引入 一個類會單獨封裝在一個獨立的文件中。 類的實例時,類的結構的定義,必須先位於記憶體中。才可以實例化對象 手動引入: 自動引入: 當實例化一個類的對象時,由PHP的自動執行機制幫我們引入此類文件。 魔術函數 __autoload();自動載入 提示:類名、類文件的名,類文件所在的目錄名 作業:... ...
  • 之後我在整理之後會把類型萃取也放著這個文章裡面,我自己還是滿容易混淆的,經常分不清、 模版的模板參數主要使用在類的類成員也是個模板類,當你想只輸入一個模板參數,就可以同時對類內的其他類成員傳入相同的模板參數的時候就可以使用咯 這個就是模板的模版參數的一個簡單實現,用來實現類的類成員和該類模板使用類型 ...
  • 1、定義一個服務 https://www.consul.io/docs/agent/services.html 該方法是服務註冊中提供服務的最常用的方法。 關於服務的定義:服務的屬性我們會在後邊每出現一個總結一個,最後再做總結。 2、服務註冊 2.1、創建服務文件所存放的文件夾 說明: .d做尾碼: ...
  • 根據導師的要求,這次的任務是要模擬一個類似BT網路的P2P網路,並實現一些演算法,查了些資料,都說NS2對於P2P網路的模擬不好,基本沒有模本可以用,而且效率很低,只能模擬幾萬個節點左右,看到挺多人推薦使用peersim,就準備下來用用看。而且在官網上看到已經有很多別人編譯好的覆蓋網路的模本,其中也包 ...
  • 外鍵 創建: 方式1:在創建表時使用foreign key(欄位名) references 表名(主鍵); 方式2:通過修改表結構add foreign key(欄位名) references 表名(主鍵); 刪除: alter table 表名 drop foreign key 外鍵名; 如果查看 ...
  • 歷屆試題 蘭頓螞蟻 時間限制:1.0s 記憶體限制:256.0MB 時間限制:1.0s 記憶體限制:256.0MB 問題描述 蘭頓螞蟻,是於1986年,由克裡斯·蘭頓提出來的,屬於細胞自動機的一種。 平面上的正方形格子被填上黑色或白色。在其中一格正方形內有一隻“螞蟻”。 螞蟻的頭部朝向為:上下左右其中一 ...
  • HashMap 的性能因數 1. 容量:表示桶位的數量。 2. 初始容量: 表在創建是所擁有的桶位數。 如果你知道將要在HashMap存儲多少項,創建一個初始容量合適的HashMap將可以避免自動再散列的開銷 /** * The default initial capacity - MUST be ... ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...