ความแตกต่างระหว่าง FetchType LAZY และ EAGER ใน Java Persistence API หรือไม่


552

ฉันเป็นมือใหม่กับ Java Persistence API และ Hibernate

ความแตกต่างระหว่างคืออะไรFetchType.LAZYและFetchType.EAGERใน Java Api คงทน?


1
การโหลดคอลเลกชันของ EAGER หมายความว่าพวกเขาถูกดึงข้อมูลอย่างสมบูรณ์ในเวลาที่ดึงพาเรนต์ ในขณะที่ EAGER กำลังโหลดลูกของฉันทั้งหมดจะถูกดึงกลับมา เด็กถูกดึงข้อมูลใน PersistentSet และ PersistentList (หรือ PersistentBag) ภายใน Persistent Bag นั้นจะแสดงเป็นรายการ Array ถูกต้องหรือไม่ ..
geetha

คำตอบ:


1064

บางครั้งคุณมีสองหน่วยงานและมีความสัมพันธ์ระหว่างพวกเขา ตัวอย่างเช่นคุณอาจมีเอนทิตีที่เรียกว่าUniversityและเอนทิตีอื่นที่เรียกว่าStudentและมหาวิทยาลัยอาจมีนักเรียนหลายคน:

หน่วยงานของมหาวิทยาลัยอาจมีคุณสมบัติพื้นฐานบางอย่างเช่น id, ชื่อ, ที่อยู่ ฯลฯ รวมถึงคุณสมบัติการรวบรวมที่เรียกว่านักเรียนที่ส่งคืนรายชื่อนักเรียนสำหรับมหาวิทยาลัยที่กำหนด:

มหาวิทยาลัยมีนักเรียนจำนวนมาก

public class University {
   private String id;
   private String name;
   private String address;
   private List<Student> students;

   // setters and getters
}

ตอนนี้เมื่อคุณโหลดมหาวิทยาลัยจากฐานข้อมูล JPA จะโหลด id, ชื่อและฟิลด์ที่อยู่ของคุณ แต่คุณมีสองตัวเลือกสำหรับวิธีการโหลดนักเรียน:

  1. หากต้องการโหลดพร้อมกับส่วนที่เหลือของฟิลด์ (เช่นกระหาย) หรือ
  2. เมื่อต้องการโหลดตามต้องการ (เช่นขี้เกียจ) เมื่อคุณเรียกgetStudents()วิธีการของมหาวิทยาลัย

เมื่อมหาวิทยาลัยมีนักเรียนจำนวนมากมันไม่ได้มีประสิทธิภาพในการโหลดนักเรียนทั้งหมดพร้อมกับมันโดยเฉพาะอย่างยิ่งเมื่อพวกเขาไม่ต้องการและในกรณีเช่นนี้คุณสามารถประกาศว่าคุณต้องการให้นักเรียนโหลดเมื่อพวกเขาต้องการจริง ๆ สิ่งนี้เรียกว่าการโหลดแบบขี้เกียจ

นี่คือตัวอย่างที่studentsมีการทำเครื่องหมายอย่างชัดเจนว่าจะโหลดอย่างกระตือรือร้น:

@Entity
public class University {

    @Id
    private String id;

    private String name;

    private String address;

    @OneToMany(fetch = FetchType.EAGER)
    private List<Student> students;

    // etc.    
}

และนี่คือตัวอย่างที่studentsมีการทำเครื่องหมายอย่างชัดเจนว่าให้โหลดอย่างเกียจคร้าน:

@Entity
public class University {

    @Id
    private String id;

    private String name;

    private String address;

    @OneToMany(fetch = FetchType.LAZY)
    private List<Student> students;

    // etc.
}

5
@BehrangSaeedzadeh คุณสามารถแสดงความแตกต่างในทางปฏิบัติหรือข้อดีและข้อเสียของการโหลดแต่ละประเภท (นอกเหนือจากประสิทธิภาพที่คุณกล่าวถึง) เหตุใดจึงต้องใช้ความกระตือรือร้นในการโหลด?
ADTC

73
@ADTC เพื่อให้การโหลดแบบขี้เกียจทำงานได้เซสชัน JDBC จะต้องยังคงเปิดอยู่เมื่อเอนทิตีเป้าหมายต้องการโหลดลงในหน่วยความจำโดยเรียกใช้วิธี getter (เช่นgetStudents()) แต่บางครั้งก็เป็นไปไม่ได้เพราะตามเวลาที่วิธีนี้ ถูกเรียกเซสชันถูกปิดไปแล้วและไม่ได้ใช้เอนทิตี ในทำนองเดียวกันบางครั้งเรามีสถาปัตยกรรมไคลเอนต์ / เซิร์ฟเวอร์ (เช่น Swing client / เซิร์ฟเวอร์ JEE) และเอนทิตี / DTOs จะถูกโอนผ่านสายไปยังไคลเอนต์และอีกครั้งบ่อยที่สุดในสถานการณ์เหล่านี้การโหลดที่ขี้เกียจจะไม่ทำงาน ถูกทำให้เป็นอนุกรมมากกว่าลวด
TheFooProgrammer

4
ฉันต้องการเพิ่มข้อมูลเพิ่มเติมลงในคำตอบนี้จากหนังสือของฉัน - เพื่อประหยัดหน่วยความจำการโหลด Lazy โดยทั่วไปจะใช้สำหรับความสัมพันธ์แบบหนึ่งต่อหนึ่งและหลายต่อหลายครั้ง สำหรับแบบหนึ่งต่อหนึ่งโดยทั่วไปจะใช้ความกระตือรือร้น
Erran Morad

2
ในการโหลดสันหลังยาวเมื่อฉันเรียกgetStudents()วิธีการนี้เป็นครั้งแรกผลลัพธ์จะถูกแคชหรือไม่ เพื่อที่ฉันจะสามารถเข้าถึงผลลัพธ์เหล่านั้นได้เร็วขึ้นในครั้งต่อไป
JavaTechnical

2
@JavaTechnical ขึ้นอยู่กับว่าคุณเปิดใช้งานแคชระดับที่สอง (เปิดใช้งานโดยค่าเริ่มต้น)
Ced

285

โดยทั่วไป

LAZY = fetch when needed
EAGER = fetch immediately

11
ชัดเจนมาก แต่หลังจากอ่านคำตอบของ @ Behang แล้ว ขอบคุณสำหรับการสรุปที่ชัดเจน :-)
Nabin

66

EAGERโหลดคอลเลกชันหมายความว่าพวกเขาจะถูกดึงอย่างเต็มที่ในเวลาที่ผู้ปกครองจะถูกดึง ดังนั้นหากคุณมีCourseและมี List<Student>นักเรียนทุกคนจะดึงข้อมูลจากฐานข้อมูลในเวลาที่Courseดึงข้อมูล

LAZYในทางตรงกันข้ามหมายความว่าเนื้อหาของListจะถูกดึงเมื่อคุณพยายามที่จะเข้าถึงพวกเขา course.getStudents().iterator()ยกตัวอย่างเช่นโดยการเรียก เรียกวิธีการเข้าถึงใด ๆ บนListจะเริ่มต้นการโทรไปยังฐานข้อมูลเพื่อดึงองค์ประกอบ สิ่งนี้ถูกนำไปใช้โดยการสร้าง Proxy รอบ ๆList(หรือSet) ดังนั้นสำหรับคอลเล็กชั่นขี้เกียจของคุณประเภทคอนกรีตจะไม่ArrayListและHashSetแต่PersistentSetและPersistentList(หรือPersistentBag)


ฉันใช้แนวคิดนั้นในการดึงรายละเอียดของเอนทิตีลูก แต่ฉันไม่เห็นความแตกต่างระหว่างพวกเขา เมื่อฉันระบุ Eager fetch มันจะดึงข้อมูลทุกอย่างและเมื่อฉันดีบักฉันเห็น "Bean deferred" ที่เอนทิตีลูก เมื่อฉันพูดcourse.getStudents()มันจะทำการสืบค้น SQL (เห็นว่าบนคอนโซล) ในประเภทการดึงข้อมูลของ Lazy สิ่งเดียวกันก็เกิดขึ้นเช่นกัน ดังนั้นอะไรคือความแตกต่าง ??
Neha Choudhary

คอลเลกชันกระตือรือร้นถูกดึงเมื่อกิจการที่เป็นเจ้าของโหลด คอลเล็กชัน Lazy ถูกดึงออกมาเมื่อคุณเข้าถึง ถ้าไม่ได้เป็นพฤติกรรมที่เห็นของคุณมีอาจจะเป็นสิ่งผิดปกติกับสภาพแวดล้อมของคุณ (เช่นทำงานรุ่นเก่าของชั้นเรียน)
Bozho

1
@Bozho คุณระบุการโหลดคอลเลกชันขี้เกียจเท่านั้น สามารถโหลดฟิลด์สตริงแบบง่ายได้หรือไม่
vikiiii

ฉบับที่คุณจำเป็นต้องใช้การสอบถามหรือนิติบุคคลแมปที่แตกต่างกันที่จะได้รับส่วนหนึ่งของคอลัมน์ที่
Bozho

@Bozho เดี๋ยวก่อนคุณสามารถโปรดตอบคำถามนี้แล้วถ้ามันตั้งอยู่บนfetchtype = LAZYหนึ่งเริ่มต้นแม้ว่าพยายามที่จะได้รับคอลเลกชันที่มี hibernete ทะเยอทะยานพ่นข้อผิดพลาดบอกฉันมันไม่สามารถประเมิน
ВсеЕдно

16

ฉันอาจพิจารณาถึงประสิทธิภาพและการใช้งานหน่วยความจำ ความแตกต่างที่สำคัญอย่างหนึ่งคือกลยุทธ์ดึงข้อมูลของ EAGER อนุญาตให้ใช้วัตถุดึงข้อมูลโดยไม่ต้องใช้เซสชัน ทำไม?
ข้อมูลทั้งหมดจะถูกดึงเมื่อกระตือรือร้นที่จะทำเครื่องหมายข้อมูลในวัตถุเมื่อเชื่อมต่อกับเซสชัน อย่างไรก็ตามในกรณีของกลยุทธ์การโหลดแบบสันหลังยาววัตถุที่ทำเครื่องหมายการโหลดแบบสันหลังยาวจะไม่ดึงข้อมูลหากเซสชันถูกตัดการเชื่อมต่อ (หลังจากsession.close()คำสั่ง) ทุกสิ่งที่สามารถทำได้โดยพร็อกซีไฮเบอร์เนต กลยุทธ์กระตือรือร้นช่วยให้ข้อมูลยังคงพร้อมใช้งานหลังจากปิดเซสชัน


11

ตามความรู้ของฉันทั้งการดึงข้อมูลขึ้นอยู่กับความต้องการของคุณ

FetchType.LAZY อยู่ในความต้องการ (เช่นเมื่อเราต้องการข้อมูล)

FetchType.EAGER เป็นทันที (เช่นก่อนที่ความต้องการของเรามาเราจะดึงข้อมูลบันทึกโดยไม่จำเป็น)


11

ตามค่าเริ่มต้นสำหรับคอลเลกชันและวัตถุแผนที่ทั้งหมดกฎการดึงข้อมูลFetchType.LAZYและสำหรับอินสแตนซ์อื่นนั้นเป็นไปตามFetchType.EAGERนโยบาย
โดยสังเขป@OneToManyและ@ManyToManyความสัมพันธ์ไม่ได้ดึงเอาวัตถุที่เกี่ยวข้อง (การรวบรวมและแผนที่) โดยนัย แต่การดำเนินการดึงข้อมูลจะถูกลดหลั่นผ่านเขตข้อมูลใน@OneToOneและ@ManyToOneวัตถุ

(มารยาท: - objectdbcom)


9

ทั้งสองFetchType.LAZYและFetchType.EAGERถูกนำมาใช้ในการกำหนดค่าเริ่มต้นดึงข้อมูลแผน

ขออภัยคุณสามารถลบล้างแผนการดึงข้อมูลเริ่มต้นสำหรับการดึงข้อมูล LAZY เท่านั้น การดึงข้อมูล EAGER นั้นมีความยืดหยุ่นน้อยกว่าและสามารถนำไปสู่ปัญหาด้านประสิทธิภาพได้มากมาย

คำแนะนำของฉันคือยับยั้งการสร้างการเชื่อมโยงของคุณ EAGER เพราะการดึงข้อมูลเป็นความรับผิดชอบของเวลาสอบถาม ดังนั้นข้อความค้นหาทั้งหมดของคุณควรใช้คำสั่งดึงข้อมูลเพื่อดึงข้อมูลสิ่งที่จำเป็นสำหรับกรณีธุรกิจปัจจุบันเท่านั้น


2
"การดึงข้อมูลของ EAGER นั้นมีความยืดหยุ่นน้อยกว่าและสามารถนำไปสู่ปัญหาด้านประสิทธิภาพหลายประการ" ... คำสั่ง truer คือ "การใช้หรือไม่ใช้การดึงข้อมูล EAGER อาจทำให้เกิดปัญหาประสิทธิภาพ" ในกรณีพิเศษนั้นเมื่อเขตข้อมูลเริ่มต้นที่ขี้เกียจมีราคาแพงในการเข้าถึงและใช้งานไม่บ่อยนักการดึงข้อมูลที่ขี้เกียจจะได้รับประโยชน์ แต่ในกรณีที่มีการใช้ตัวแปรบ่อยครั้งการเริ่มต้นแบบขี้เกียจสามารถทำให้ประสิทธิภาพลดลงได้โดยต้องการการเดินทางไปยังฐานข้อมูลมากกว่าการเริ่มต้นด้วยความกระตือรือร้น ฉันขอแนะนำให้ใช้ FetchType อย่างถูกต้องไม่ใช่แบบดันทุรัง
กอตต์

คุณโปรโมตหนังสือของคุณที่นี่ !! แต่ใช่ฉันรู้สึกว่ามันขึ้นอยู่กับกรณีการใช้งานและขนาดของวัตถุที่ถูกอ้างถึงในความสัมพันธ์ของ cardinality
John Doe

6

จากJavadoc :

กลยุทธ์ EAGER เป็นข้อกำหนดของผู้ให้บริการคงอยู่ที่ข้อมูลจะต้องดึงข้อมูลอย่างกระตือรือร้น กลยุทธ์ของ LAZY คือคำใบ้ของผู้ให้บริการคงอยู่ที่ข้อมูลควรถูกเรียกอย่างเกียจคร้านเมื่อมีการเข้าถึงครั้งแรก

เช่นความกระตือรือร้นในเชิงรุกมากกว่าขี้เกียจ Lazy จะเกิดขึ้นเมื่อใช้ครั้งแรกเท่านั้น (หากผู้ให้บริการใช้คำใบ้) ในขณะที่มีสิ่งที่กระตือรือร้น (อาจ) ได้รับการดึงข้อมูลล่วงหน้า


1
"ใช้งานครั้งแรก" คุณหมายถึงอะไร
leon

@leon: สมมติว่าคุณมีเอนทิตีที่มีฟิลด์กระตือรือร้นและฟิลด์ขี้เกียจ เมื่อคุณได้รับเอนทิตีฟิลด์กระตือรือร้นจะถูกโหลดจาก DB ตามเวลาที่คุณได้รับการอ้างอิงเอนทิตี แต่ฟิลด์ขี้เกียจอาจไม่ได้รับ มันจะถูกดึงข้อมูลเฉพาะเมื่อคุณพยายามเข้าถึงฟิลด์ผ่าน accessor ของมัน
TJ Crowder

@TJ Crowder สิ่งที่เป็นค่าเริ่มต้นเมื่อไม่ได้กำหนด fetchtype?
Mahmoud Saleh

@MahmoudSaleh: ฉันไม่มีความคิด มันอาจแตกต่างกันไปขึ้นอยู่กับบางสิ่งบางอย่าง ฉันไม่ได้ใช้ JPA ในโครงการจริงดังนั้นฉันจึงไม่ได้รับความกล้าหาญจากมัน
TJ Crowder

2
@MahmoudS: fetchtypes เริ่มต้น: OneToMany: LAZY, ManyToOne: EAGER, ManyToMany: LAZY, OneToOne: EAGER, คอลัมน์: EAGER
Markus Pscheidt

5

LazyFetch ประเภทเป็นค่าเริ่มต้นเลือกโดย Hibernate เว้นแต่ว่าคุณได้ทำเครื่องหมายEagerFetch ประเภท เพื่อความแม่นยำและรัดกุมยิ่งขึ้นสามารถระบุความแตกต่างได้ดังต่อไปนี้

FetchType.LAZY = สิ่งนี้ไม่ได้โหลดความสัมพันธ์เว้นแต่ว่าคุณจะเรียกใช้ผ่านวิธีการทะลุผ่าน

FetchType.EAGER = สิ่งนี้จะโหลดความสัมพันธ์ทั้งหมด

ข้อดีและข้อเสียของการดึงข้อมูลทั้งสองประเภท

Lazy initialization ปรับปรุงประสิทธิภาพโดยหลีกเลี่ยงการคำนวณที่ไม่จำเป็นและลดความต้องการหน่วยความจำ

Eager initialization ใช้หน่วยความจำมากขึ้นและความเร็วในการประมวลผลช้า

ต้องบอกว่าขึ้นอยู่กับสถานการณ์อย่างใดอย่างหนึ่งของการเริ่มต้นเหล่านี้สามารถนำมาใช้


1
คำแถลงว่า "ไม่ได้โหลดความสัมพันธ์เว้นแต่คุณจะเรียกมันผ่านวิธีการทะเยอทะยาน" เป็นสิ่งสำคัญที่จะต้องทราบและยังมีการตัดสินใจการออกแบบที่ค่อนข้างปัญญาอ่อนในความมั่นใจของฉัน ... ฉันเพิ่งพบกรณีที่ฉันคิดว่ามันจะดึงมันเมื่อเข้าถึงและ มันไม่ได้เพราะฉันไม่ได้เรียกฟังก์ชัน getter โดยปริยาย โดยวิธีการที่ฟังก์ชั่น "ทะเยอทะยาน" คืออะไร? JPA จะเลื่อนการโหลดคุณสมบัติจนกว่าจะเรียกใช้ฟังก์ชันที่เรียกgetMemberว่าตรงกับรูปแบบชื่อของสมาชิกหรือไม่
ToVine

3

Book.java

        import java.io.Serializable;
        import javax.persistence.Column;
        import javax.persistence.Entity;
        import javax.persistence.GeneratedValue;
        import javax.persistence.GenerationType;
        import javax.persistence.Id;
        import javax.persistence.ManyToOne;
        import javax.persistence.Table;

        @Entity
        @Table(name="Books")
        public class Books implements Serializable{

        private static final long serialVersionUID = 1L;
        @Id
        @GeneratedValue(strategy=GenerationType.IDENTITY)
        @Column(name="book_id")
        private int id;
        @Column(name="book_name")
        private String name;

        @Column(name="author_name")
        private String authorName;

        @ManyToOne
        Subject subject;

        public Subject getSubject() {
            return subject;
        }
        public void setSubject(Subject subject) {
            this.subject = subject;
        }

        public int getId() {
            return id;
        }
        public void setId(int id) {
            this.id = id;
        }
        public String getName() {
            return name;
        }
        public void setName(String name) {
            this.name = name;
        }
        public String getAuthorName() {
            return authorName;
        }
        public void setAuthorName(String authorName) {
            this.authorName = authorName;
        }

        }

Subject.java

    import java.io.Serializable;
    import java.util.ArrayList;
    import java.util.List;
    import javax.persistence.CascadeType;
    import javax.persistence.Column;
    import javax.persistence.Entity;
    import javax.persistence.FetchType;
    import javax.persistence.GeneratedValue; 
    import javax.persistence.GenerationType;
    import javax.persistence.Id;
    import javax.persistence.OneToMany;
    import javax.persistence.Table;

    @Entity
    @Table(name="Subject")
    public class Subject implements Serializable{

    private static final long serialVersionUID = 1L;
    @Id
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    @Column(name="subject_id")
    private int id;
    @Column(name="subject_name")
    private String name;
    /**
    Observe carefully i have mentioned fetchType.EAGER. By default its is fetchType.LAZY for @OneToMany i have mentioned it but not required. Check the Output by changing it to fetchType.EAGER
    */

    @OneToMany(mappedBy="subject",cascade=CascadeType.ALL,fetch=FetchType.LAZY,
orphanRemoval=true)
    List<Books> listBooks=new ArrayList<Books>();

    public List<Books> getListBooks() {
        return listBooks;
    }
    public void setListBooks(List<Books> listBooks) {
        this.listBooks = listBooks;
    }
    public int getId() {
        return id;
    }
    public void setId(int id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }

    }

HibernateUtil.java

import org.hibernate.SessionFactory;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
import org.hibernate.cfg.Configuration;
public class HibernateUtil {

 private static SessionFactory sessionFactory ;
 static {
    Configuration configuration = new Configuration();
    configuration.addAnnotatedClass (Com.OneToMany.Books.class);
    configuration.addAnnotatedClass (Com.OneToMany.Subject.class);
    configuration.setProperty("connection.driver_class","com.mysql.jdbc.Driver");
    configuration.setProperty("hibernate.connection.url", "jdbc:mysql://localhost:3306/hibernate");                                
    configuration.setProperty("hibernate.connection.username", "root");     
    configuration.setProperty("hibernate.connection.password", "root");
    configuration.setProperty("dialect", "org.hibernate.dialect.MySQLDialect");
    configuration.setProperty("hibernate.hbm2ddl.auto", "update");
    configuration.setProperty("hibernate.show_sql", "true");
    configuration.setProperty(" hibernate.connection.pool_size", "10");
    configuration.setProperty(" hibernate.cache.use_second_level_cache", "true");
    configuration.setProperty(" hibernate.cache.use_query_cache", "true");
    configuration.setProperty(" cache.provider_class", "org.hibernate.cache.EhCacheProvider");
    configuration.setProperty("hibernate.cache.region.factory_class" ,"org.hibernate.cache.ehcache.EhCacheRegionFactory");

   // configuration
    StandardServiceRegistryBuilder builder = new StandardServiceRegistryBuilder().applySettings(configuration.getProperties());
    sessionFactory = configuration.buildSessionFactory(builder.build());
 }
public static SessionFactory getSessionFactory() {
    return sessionFactory;
}
} 

Main.java

    import org.hibernate.Session;
    import org.hibernate.SessionFactory;

    public class Main {

    public static void main(String[] args) {
        SessionFactory factory=HibernateUtil.getSessionFactory();
        save(factory);
        retrieve(factory);

    }

     private static void retrieve(SessionFactory factory) {
        Session session=factory.openSession();
        try{
            session.getTransaction().begin();
            Subject subject=(Subject)session.get(Subject.class, 1);
            System.out.println("subject associated collection is loading lazily as @OneToMany is lazy loaded");

            Books books=(Books)session.get(Books.class, 1);
            System.out.println("books associated collection is loading eagerly as by default @ManyToOne is Eagerly loaded");
            /*Books b1=(Books)session.get(Books.class, new Integer(1));

            Subject sub=session.get(Subject.class, 1);
            sub.getListBooks().remove(b1);
            session.save(sub);
            session.getTransaction().commit();*/
        }catch(Exception e){
            e.printStackTrace();
        }finally{
            session.close();
        }

        }

       private static void save(SessionFactory factory){
        Subject subject=new Subject();
        subject.setName("C++");

        Books books=new Books();
        books.setAuthorName("Bala");
        books.setName("C++ Book");
        books.setSubject(subject);

        subject.getListBooks().add(books);
        Session session=factory.openSession();
        try{
        session.beginTransaction();

        session.save(subject);

        session.getTransaction().commit();
        }catch(Exception e){
            e.printStackTrace();
        }finally{
            session.close();
        }
    }

    }

ตรวจสอบวิธีการดึงข้อมูล () ของ Main.java เมื่อเราได้รับหัวเรื่องจากนั้นรายการคอลเลกชันหนังสือที่มีคำอธิบายประกอบ@OneToManyจะถูกโหลดอย่างเกียจคร้าน แต่ในทางกลับกันสมาคมที่เกี่ยวข้องกับหนังสือเกี่ยวกับคอลเลกชันที่มีคำอธิบายประกอบ@ManyToOneโหลดโหลดอย่างช้าๆ (โดย[default][1]for @ManyToOne, fetchType=EAGER) เราสามารถเปลี่ยนพฤติกรรมโดยวาง fetchType.EAGER ใน@OneToManySubject.java หรือ fetchType.LAZY @ManyToOneใน Books.java


1

public enum FetchType ขยาย java.lang.Enum กำหนดกลยุทธ์สำหรับการดึงข้อมูลจากฐานข้อมูล กลยุทธ์ EAGER เป็นข้อกำหนดของผู้ให้บริการคงอยู่ที่ข้อมูลจะต้องดึงข้อมูลอย่างกระตือรือร้น กลยุทธ์ของ LAZY คือคำใบ้ของผู้ให้บริการคงอยู่ที่ข้อมูลควรถูกเรียกอย่างเกียจคร้านเมื่อมีการเข้าถึงครั้งแรก การดำเนินการได้รับอนุญาตให้ดึงข้อมูลอย่างกระตือรือร้นซึ่งคำใบ้กลยุทธ์ของ LAZY ได้ถูกระบุไว้ ตัวอย่าง: @Basic (fetch = LAZY) String ที่ป้องกัน getName () {ชื่อคืน; }

แหล่ง


1

ฉันต้องการที่จะเพิ่มบันทึกนี้ในสิ่งที่ "Kyung Hwan Min" กล่าวไว้ข้างต้น

สมมติว่าคุณกำลังใช้ Spring Rest กับสถาปนิกที่เรียบง่ายนี้:

คอนโทรลเลอร์ <-> บริการ <-> พื้นที่เก็บข้อมูล

และคุณต้องการส่งคืนข้อมูลบางส่วนไปยังส่วนหน้าหากคุณใช้FetchType.LAZYคุณจะได้รับข้อยกเว้นหลังจากที่คุณส่งคืนข้อมูลไปยังวิธีการควบคุมเนื่องจากเซสชันถูกปิดในบริการดังนั้นจึงJSON Mapper Objectไม่สามารถรับข้อมูลได้

มีสามตัวเลือกทั่วไปในการแก้ปัญหานี้ขึ้นอยู่กับการออกแบบประสิทธิภาพและนักพัฒนา:

  1. วิธีที่ง่ายที่สุดคือใช้FetchType.EAGERเพื่อให้เซสชันยังคงอยู่ที่วิธีการควบคุม
  2. โซลูชั่นต่อต้านรูปแบบเพื่อให้เซสชันมีชีวิตอยู่จนกว่าการดำเนินการจะสิ้นสุดลงจึงทำให้เกิดปัญหาด้านประสิทธิภาพอย่างมากในระบบ
  3. วิธีปฏิบัติที่ดีที่สุดคือใช้FetchType.LAZYกับวิธีการแปลงเพื่อถ่ายโอนข้อมูลจากEntityไปยังวัตถุข้อมูลอื่นDTOและส่งไปยังตัวควบคุมดังนั้นจึงไม่มีข้อยกเว้นหากปิดเซสชัน


0

@ drop-shadow ถ้าคุณใช้ Hibernate คุณสามารถโทรหาHibernate.initialize()เมื่อคุณเรียกใช้getStudents()เมธอด:

Public class UniversityDaoImpl extends GenericDaoHibernate<University, Integer> implements UniversityDao {
    //...
    @Override
    public University get(final Integer id) {
        Query query = getQuery("from University u where idUniversity=:id").setParameter("id", id).setMaxResults(1).setFetchSize(1);
        University university = (University) query.uniqueResult();
        ***Hibernate.initialize(university.getStudents());***
        return university;
    }
    //...
}

0

LAZY: มันดึงเอนทิตี้ของเด็กอย่างขี้เกียจนั่นคือตอนที่ดึงเอนทิตี้ของพาเรนต์มันเพิ่งดึงพร็อกซี (สร้างโดย cglib หรือยูทิลิตี้อื่น ๆ ) ของเอนทิตีลูกและเมื่อคุณเข้าถึงคุณสมบัติของเอนทิตีลูก

EAGER: ดึงเอนทิตีย่อยพร้อมกับพาเรนต์

เพื่อความเข้าใจที่ดีขึ้นให้ไปที่เอกสาร Jboss หรือคุณสามารถใช้hibernate.show_sql=trueแอพของคุณและตรวจสอบคำสั่งที่จำศีลของไฮเบอร์เนต

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.