簡體   English   中英

Spring Boot,無法延遲初始化角色集合,無法初始化代理 - 沒有會話

[英]Spring Boot, Failed to lazily initialize a collection of role, could not initialize proxy - no Session

我正在制作一個網站,我試圖在其中訂購配料。 我選擇配料並輸入其數量,然后單擊添加。 我重復幾次。 然后我轉到下一頁,我在其中選擇了供應商。 然后我按“訂單”。

預計將 Nabavka 插入數據庫並打開一個頁面說訂單成功,但我得到一個異常,告訴我我不能懶惰地初始化它。

從 NabavkaController.java:

@Autowired
NamirnicaRepository namr;
@Autowired
NabavkaRepository nabr;
@Autowired
DobavljacRepository dr;
@Autowired
NabavkaKorpaRepository nkr;...

@SuppressWarnings("unchecked")
@PostMapping(value = "sacuvajNabavku")
public String sacuvajNabavku(Dobavljac dobavljac, HttpServletRequest request) {
    List<Namirnica> izabrane = (ArrayList<Namirnica>) request.getSession()
            .getAttribute("izabrane");
    List<Integer> brojevi = (ArrayList<Integer>) request.getSession()
            .getAttribute("brojevi");
    Nabavka n = new Nabavka();
    for (int i = 0; i < izabrane.size(); i++) {
        System.out.println(izabrane.get(i).getNaziv());
        NabavkaKorpaPK nkPK = new NabavkaKorpaPK();
        nkPK.setIdNabavka(n.getIdNabavka());
        nkPK.setIdNamirnica(izabrane.get(i).getIdNamirnica());

        NabavkaKorpa nk = new NabavkaKorpa();
        nk.setId(nkPK);
        nk.setKolicina(brojevi.get(i));
        nk.setUkupnaCena(izabrane.get(i).getCenaNamirnice() * brojevi.get(0));
        izabrane.get(i).addNabavkaKorpa(nk);

        n.addNabavkaKorpa(nk);
        nabr.updateNamirnica(izabrane.get(i));
    }
    n.setDatumNabavke(new Date());
    n.setUkupnaCena(n.getNabavkaKorpas().stream().map(k -> k.getUkupnaCena()).reduce(0.0,
            (a, b) -> a + b));
    n.setDobavljac(dobavljac);
    dobavljac.addNabavka(n);
    nabr.save(n);
    return "uspehNabavka";
}

納巴夫卡.java:

@Entity
@NamedQuery(name="Nabavka.findAll", query="SELECT n FROM Nabavka n")
public class Nabavka implements Serializable {
    private static final long serialVersionUID = 1L;

    @Id
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    private int idNabavka;

    @Temporal(TemporalType.TIMESTAMP)
    private Date datumNabavke;

    private double ukupnaCena;

    //bi-directional many-to-one association to Dobavljac
    @ManyToOne
    @JoinColumn(name="idDobavljac")
    private Dobavljac dobavljac;

    //bi-directional many-to-one association to Menadzer
    @ManyToOne
    @JoinColumns({
        @JoinColumn(name="idMenadzer", referencedColumnName="idMenadzer"),
        @JoinColumn(name="idRadnik", referencedColumnName="idRadnik")
        })
    private Menadzer menadzer;

    //bi-directional many-to-one association to User
    @ManyToOne
    @JoinColumn(name="idUser")
    private User user;

    //bi-directional many-to-one association to NabavkaKorpa
    @OneToMany(mappedBy="nabavka", cascade={CascadeType.ALL})
    private List<NabavkaKorpa> nabavkaKorpas = new ArrayList<NabavkaKorpa>();

    public Nabavka() {
    }

    public int getIdNabavka() {
        return this.idNabavka;
    }

    public void setIdNabavka(int idNabavka) {
        this.idNabavka = idNabavka;
    }

    public Date getDatumNabavke() {
        return this.datumNabavke;
    }

    public void setDatumNabavke(Date datumNabavke) {
        this.datumNabavke = datumNabavke;
    }

    public double getUkupnaCena() {
        return this.ukupnaCena;
    }

    public void setUkupnaCena(double ukupnaCena) {
        this.ukupnaCena = ukupnaCena;
    }

    public Dobavljac getDobavljac() {
        return this.dobavljac;
    }

    public void setDobavljac(Dobavljac dobavljac) {
        this.dobavljac = dobavljac;
    }

    public Menadzer getMenadzer() {
        return this.menadzer;
    }

    public void setMenadzer(Menadzer menadzer) {
        this.menadzer = menadzer;
    }

    public User getUser() {
        return this.user;
    }

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

    public List<NabavkaKorpa> getNabavkaKorpas() {
        return this.nabavkaKorpas;
    }

    public void setNabavkaKorpas(List<NabavkaKorpa> nabavkaKorpas) {
        this.nabavkaKorpas = nabavkaKorpas;
    }

    public NabavkaKorpa addNabavkaKorpa(NabavkaKorpa nabavkaKorpa) {
        getNabavkaKorpas().add(nabavkaKorpa);
        nabavkaKorpa.setNabavka(this);

        return nabavkaKorpa;
    }

    public NabavkaKorpa removeNabavkaKorpa(NabavkaKorpa nabavkaKorpa) {
        getNabavkaKorpas().remove(nabavkaKorpa);
        nabavkaKorpa.setNabavka(null);

        return nabavkaKorpa;
    }

}

Namirnica.java:

@Entity
@NamedQuery(name="Namirnica.findAll", query="SELECT n FROM Namirnica n")
public class Namirnica implements Serializable {
    private static final long serialVersionUID = 1L;

    @Id
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    private int idNamirnica;

    private double cenaNamirnice;

    private String kolicina;

    private String naziv;
    
    private int stanje;

    //bi-directional many-to-one association to NabavkaKorpa
    @OneToMany(mappedBy="namirnica")
    private List<NabavkaKorpa> nabavkaKorpas = new ArrayList<NabavkaKorpa>();

    public Namirnica() {
    }

    public int getIdNamirnica() {
        return this.idNamirnica;
    }

    public void setIdNamirnica(int idNamirnica) {
        this.idNamirnica = idNamirnica;
    }

    public double getCenaNamirnice() {
        return this.cenaNamirnice;
    }

    public void setCenaNamirnice(double cenaNamirnice) {
        this.cenaNamirnice = cenaNamirnice;
    }

    public String getKolicina() {
        return this.kolicina;
    }

    public void setKolicina(String kolicina) {
        this.kolicina = kolicina;
    }

    public String getNaziv() {
        return this.naziv;
    }

    public void setNaziv(String naziv) {
        this.naziv = naziv;
    }
    
    public int getStanje() {
        return this.stanje;
    }

    public void setStanje(int stanje) {
        this.stanje = stanje;
    }

    public List<NabavkaKorpa> getNabavkaKorpas() {
        return this.nabavkaKorpas;
    }

    public void setNabavkaKorpas(List<NabavkaKorpa> nabavkaKorpas) {
        this.nabavkaKorpas = nabavkaKorpas;
    }

    public NabavkaKorpa addNabavkaKorpa(NabavkaKorpa nabavkaKorpa) {
        getNabavkaKorpas().add(nabavkaKorpa);
        nabavkaKorpa.setNamirnica(this);

        return nabavkaKorpa;
    }

    public NabavkaKorpa removeNabavkaKorpa(NabavkaKorpa nabavkaKorpa) {
        getNabavkaKorpas().remove(nabavkaKorpa);
        nabavkaKorpa.setNamirnica(null);

        return nabavkaKorpa;
    }

}

NabavkaKorpa.java:

@Entity
@NamedQuery(name="NabavkaKorpa.findAll", query="SELECT n FROM NabavkaKorpa n")
public class NabavkaKorpa implements Serializable {
    private static final long serialVersionUID = 1L;

    @EmbeddedId
    private NabavkaKorpaPK id;

    private int kolicina;

    private double ukupnaCena;

    //bi-directional many-to-one association to Nabavka
    @ManyToOne(cascade={CascadeType.ALL})
    @JoinColumn(name="idNabavka", insertable = false, updatable = false)
    private Nabavka nabavka;

    //bi-directional many-to-one association to Namirnica
    @ManyToOne(cascade={CascadeType.ALL})
    @JoinColumn(name="idNamirnica", insertable = false, updatable = false)
    private Namirnica namirnica;

    public NabavkaKorpa() {
    }

    public NabavkaKorpaPK getId() {
        return this.id;
    }

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

    public int getKolicina() {
        return this.kolicina;
    }

    public void setKolicina(int kolicina) {
        this.kolicina = kolicina;
    }

    public double getUkupnaCena() {
        return this.ukupnaCena;
    }

    public void setUkupnaCena(double ukupnaCena) {
        this.ukupnaCena = ukupnaCena;
    }

    public Nabavka getNabavka() {
        return this.nabavka;
    }

    public void setNabavka(Nabavka nabavka) {
        this.nabavka = nabavka;
    }

    public Namirnica getNamirnica() {
        return this.namirnica;
    }

    public void setNamirnica(Namirnica namirnica) {
        this.namirnica = namirnica;
    }

}

NabavkaKorpaPK.java:

@Embeddable
public class NabavkaKorpaPK implements Serializable {
    //default serial version id, required for serializable classes.
    private static final long serialVersionUID = 1L;

    @Column(insertable=false, updatable=false)
    private int idNamirnica;

    @Column(insertable=false, updatable=false)
    private int idNabavka;

    public NabavkaKorpaPK() {
    }
    public int getIdNamirnica() {
        return this.idNamirnica;
    }
    public void setIdNamirnica(int idNamirnica) {
        this.idNamirnica = idNamirnica;
    }
    public int getIdNabavka() {
        return this.idNabavka;
    }
    public void setIdNabavka(int idNabavka) {
        this.idNabavka = idNabavka;
    }

    public boolean equals(Object other) {
        if (this == other) {
            return true;
        }
        if (!(other instanceof NabavkaKorpaPK)) {
            return false;
        }
        NabavkaKorpaPK castOther = (NabavkaKorpaPK)other;
        return 
            (this.idNamirnica == castOther.idNamirnica)
            && (this.idNabavka == castOther.idNabavka);
    }

    public int hashCode() {
        final int prime = 31;
        int hash = 17;
        hash = hash * prime + this.idNamirnica;
        hash = hash * prime + this.idNabavka;
        
        return hash;
    }
}

NabavkaKorpaRepository.java:

public interface NabavkaKorpaRepository extends JpaRepository<NabavkaKorpa, NabavkaKorpaPK> {

}

NabavkaRepository.java:

public interface NabavkaRepository extends JpaRepository<Nabavka, Integer>, NabavkaRepoSpecific {

}

NabavkaRepoSpeicific.java

public interface NabavkaRepoSpecific {

    public void updateNamirnica(Namirnica namirnica);

}

NabavkaRepoSpecificImpl.java:

@Repository
@Transactional
public class NabavkaRepoSpecificImpl implements NabavkaRepoSpecific {

    @PersistenceContext
    EntityManager em;

    @Override
    public void updateNamirnica(Namirnica namirnica) {
        try {
            em.merge(namirnica);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

}

NamirnicaRepository.java:

public interface NamirnicaRepository extends JpaRepository<Namirnica, Integer> {

}

例外:

org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: model.Namirnica.nabavkaKorpas, could not initialize proxy - no Session
    at org.hibernate.collection.internal.AbstractPersistentCollection.throwLazyInitializationException(AbstractPersistentCollection.java:614) ~[hibernate-core-5.6.9.Final.jar:5.6.9.Final]
    at org.hibernate.collection.internal.AbstractPersistentCollection.withTemporarySessionIfNeeded(AbstractPersistentCollection.java:218) ~[hibernate-core-5.6.9.Final.jar:5.6.9.Final]
    at org.hibernate.collection.internal.AbstractPersistentCollection.initialize(AbstractPersistentCollection.java:591) ~[hibernate-core-5.6.9.Final.jar:5.6.9.Final]
    at org.hibernate.collection.internal.AbstractPersistentCollection.write(AbstractPersistentCollection.java:415) ~[hibernate-core-5.6.9.Final.jar:5.6.9.Final]
    at org.hibernate.collection.internal.PersistentBag.add(PersistentBag.java:407) ~[hibernate-core-5.6.9.Final.jar:5.6.9.Final]
    at model.Namirnica.addNabavkaKorpa(Namirnica.java:85) ~[classes/:na]
    at com.example.demo.controller.NabavkaController.sacuvajNabavku(NabavkaController.java:95) ~[classes/:na]
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na]
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) ~[na:na]
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na]
    at java.base/java.lang.reflect.Method.invoke(Method.java:568) ~[na:na]
    at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:205) ~[spring-web-5.3.21.jar:5.3.21]
    at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:150) ~[spring-web-5.3.21.jar:5.3.21]
    at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:117) ~[spring-webmvc-5.3.21.jar:5.3.21]
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:895) ~[spring-webmvc-5.3.21.jar:5.3.21]
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:808) ~[spring-webmvc-5.3.21.jar:5.3.21]
    at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87) ~[spring-webmvc-5.3.21.jar:5.3.21]
    at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1067) ~[spring-webmvc-5.3.21.jar:5.3.21]
    at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:963) ~[spring-webmvc-5.3.21.jar:5.3.21]
    at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006) ~[spring-webmvc-5.3.21.jar:5.3.21]
    at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:909) ~[spring-webmvc-5.3.21.jar:5.3.21]
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:681) ~[tomcat-embed-core-9.0.64.jar:4.0.FR]
    at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883) ~[spring-webmvc-5.3.21.jar:5.3.21]
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:764) ~[tomcat-embed-core-9.0.64.jar:4.0.FR]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:227) ~[tomcat-embed-core-9.0.64.jar:9.0.64]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) ~[tomcat-embed-core-9.0.64.jar:9.0.64]
    at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53) ~[tomcat-embed-websocket-9.0.64.jar:9.0.64]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) ~[tomcat-embed-core-9.0.64.jar:9.0.64]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) ~[tomcat-embed-core-9.0.64.jar:9.0.64]
    at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100) ~[spring-web-5.3.21.jar:5.3.21]
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117) ~[spring-web-5.3.21.jar:5.3.21]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) ~[tomcat-embed-core-9.0.64.jar:9.0.64]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) ~[tomcat-embed-core-9.0.64.jar:9.0.64]
    at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93) ~[spring-web-5.3.21.jar:5.3.21]
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117) ~[spring-web-5.3.21.jar:5.3.21]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) ~[tomcat-embed-core-9.0.64.jar:9.0.64]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) ~[tomcat-embed-core-9.0.64.jar:9.0.64]
    at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201) ~[spring-web-5.3.21.jar:5.3.21]
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117) ~[spring-web-5.3.21.jar:5.3.21]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) ~[tomcat-embed-core-9.0.64.jar:9.0.64]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) ~[tomcat-embed-core-9.0.64.jar:9.0.64]
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:197) ~[tomcat-embed-core-9.0.64.jar:9.0.64]
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:97) ~[tomcat-embed-core-9.0.64.jar:9.0.64]
    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:541) ~[tomcat-embed-core-9.0.64.jar:9.0.64]
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:135) ~[tomcat-embed-core-9.0.64.jar:9.0.64]
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92) ~[tomcat-embed-core-9.0.64.jar:9.0.64]
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:78) ~[tomcat-embed-core-9.0.64.jar:9.0.64]
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:360) ~[tomcat-embed-core-9.0.64.jar:9.0.64]
    at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:399) ~[tomcat-embed-core-9.0.64.jar:9.0.64]
    at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65) ~[tomcat-embed-core-9.0.64.jar:9.0.64]
    at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:890) ~[tomcat-embed-core-9.0.64.jar:9.0.64]
    at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1787) ~[tomcat-embed-core-9.0.64.jar:9.0.64]
    at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) ~[tomcat-embed-core-9.0.64.jar:9.0.64]
    at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1191) ~[tomcat-embed-core-9.0.64.jar:9.0.64]
    at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659) ~[tomcat-embed-core-9.0.64.jar:9.0.64]
    at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) ~[tomcat-embed-core-9.0.64.jar:9.0.64]
    at java.base/java.lang.Thread.run(Thread.java:833) ~[na:na]

編輯:我從一個會話中得到了 Namirnicas。 這是 GitHub鏈接

錯誤的原因是您在流程的一個步驟(讓我們將其命名為A )獲得列表List<Namirnica> izabrane ,但在第二步( B )使用Namirinica項目。

默認情況下,此列表是惰性的。 這意味着您只能在A點訪問它(當@Transaction /Persistent Context/Hibernate Session 打開時)。

@OneToMany(mappedBy="namirnica")
private List<NabavkaKorpa> nabavkaKorpas = new ArrayList<NabavkaKorpa>();

即使在B點打開一個新事務也無濟於事,因為它將是另一個 Persistent context/Hibernate 會話(與A點不同)。

您可以嘗試制作nabavkaKorpas EAGER ,可能會有所幫助。 但是你有一個設計問題。

通則

永遠不要使用來自@OneToMany部分的關聯集合。

怎么修

你必須保存一個新的NabavkaKorpa ,而不是Namirnica

NabavkaKorpa nabavka = new NabavkaKorpa();
nabavka.setNamirnica(namirnica);

nabavkaKorpaRepositiry.save(nabavka);

你甚至不需要Namirnica來做到這一點。

對於休眠

Namirnica namirnica= new Namirnica();
namirnica.setId(namirnicaId);

NabavkaKorpa nabavka = new NabavkaKorpa();
nabavka.setNamirnica(namirnica);

nabavkaKorpaRepositiry.save(nabavka);

對於 Spring Data(沒有額外的查詢來從數據庫中獲取 Namirnica)

Namirnica namirnica= namirinicaRepositiry.getOne(namirnicaId);

NabavkaKorpa nabavka = new NabavkaKorpa();
nabavka.setNamirnica(namirnica);

nabavkaKorpaRepositiry.save(nabavka);

關於持久上下文的注釋

當你在方法上使用@Transactional注解時,該方法內部不僅有一個打開的事務,而且還打開了Persistent Context/Hibernate Session。 所以這種在 Spring 中廣泛使用的@Transactional方法有點混亂。

當 Persistent Context 打開時,Hibernate 會觀察對持久對象所做的所有更改,例如NamirnicaNabavkaKorpa ,並嘗試將它們保存到數據庫中,因此您甚至不需要調用存儲庫的save()方法(但我更喜歡顯式調用它)。 因此,在這種情況下,您可能可以從兩個方面保持關聯處於有效狀態: Namirnica在列表中有NabavkaKorpa並且NabavkaKorpa指的是Namirnica 但通常我不會保留這些東西。

當 Persistent Context 關閉時,Hibernate 不會觀察更改,您不必將關聯保持在有效狀態。 當您調用存儲庫方法時,會為每個此類調用創建一個單獨的持久上下文。 並且所有這樣的調用都獨立於 Hibernate 的觀點。 您可以啟用 SQL 日志記錄並查看會發生什么。

所以你不需要做

izabrane.get(i).addNabavkaKorpa(nk);

只需與NabavkaKorpa

筆記

在這里有CascadeType.ALL是一個非常糟糕的主意。

@ManyToOne(cascade={CascadeType.ALL})
@JoinColumn(name="idNamirnica", insertable = false, updatable = false)
private Namirnica namirnica;

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM