เมื่อใดและเพราะเหตุใดเอนทิตี JPA ควรใช้อินเตอร์เฟสที่สามารถทำให้เป็นอนุกรมได้


151

คำถามอยู่ในชื่อเรื่อง ด้านล่างฉันเพิ่งอธิบายความคิดและข้อสรุปบางอย่างของฉัน

เมื่อฉันมีรูปแบบโดเมนที่ง่ายมาก (3 ตารางโดยไม่มีความสัมพันธ์ใด ๆ ) องค์กรของฉันทั้งหมดไม่ได้ใช้ Serializable

แต่เมื่อโมเดลโดเมนมีความซับซ้อนมากขึ้นฉันก็มี RuntimeException ซึ่งบอกว่าหนึ่งในเอนทิตีของฉันไม่ได้ใช้ Serializable

ฉันใช้ Hibernate เป็นการนำ JPA ไปใช้

ฉันสงสัยว่า:

  1. มันเป็นข้อกำหนด / พฤติกรรมเฉพาะของผู้ขายหรือไม่?
  2. เกิดอะไรขึ้นกับเอนทิตีที่เป็นอนุกรมของฉัน พวกเขาควรจะเป็นแบบอนุกรมสำหรับการจัดเก็บหรือถ่ายโอน?
  3. ในขณะใดที่จำเป็นต้องทำให้เอนทิตีของฉันเป็นอนุกรม?

คำตอบ:


59

สิ่งนี้มักจะเกิดขึ้นหากคุณผสม HQL และแบบสอบถาม SQL ดั้งเดิม ใน HQL ไฮเบอร์เนตจะแมปประเภทที่คุณส่งไปยังฐานข้อมูลที่เข้าใจ เมื่อคุณรัน Native SQL คุณต้องทำการแมปด้วยตัวเอง ถ้าคุณไม่ทำเช่นนั้นการทำแผนที่เริ่มต้นคือการทำให้เป็นอันดับพารามิเตอร์และส่งไปยังฐานข้อมูล (หวังว่ามันจะเข้าใจมัน)


สิ่งนี้ไม่ได้อธิบายว่าทำไม "อาจเป็นอย่างไร" ดูคำตอบด้านล่างจาก Bozho
chrips

หมายความว่าเอนทิตีจะถูกบันทึกในฐานข้อมูลโดยไม่ต้องใช้ส่วนต่อประสานที่ปรับค่าได้หรือไม่
Hanumantha_3048092

@ Hanumantha_3048092 ใช่ การแมปเอนทิตีและSerializableเป็นแนวคิดที่แตกต่างกันสองแบบ
Aaron Digulla

@AaronDigulla คุณช่วยอธิบายมันด้วยตัวอย่างหรือหลอกรหัสได้ไหม
sdindiver

110

ตาม JPA Spec:

หากอินสแตนซ์ของเอนทิตีจะต้องถูกส่งผ่านโดยค่าเป็นวัตถุเดี่ยว (เช่นผ่านอินเทอร์เฟซระยะไกล) คลาสเอนทิตีจะต้องใช้อินเตอร์เฟส Serializable

"JSR 220: Enterprise JavaBeansTM, เวอร์ชัน 3.0 Java Persistence API เวอร์ชัน 3.0, การนำออกใช้ครั้งสุดท้าย 2 พฤษภาคม 2549"


14
(+1) การดูข้อมูลจำเพาะนั้นมีผลเสมอ
Bozho

20
ฉันล้มเหลวที่จะดูว่าทำไมถึงมี upvotes มากมาย OP บอกว่าไม่จำเป็นเมื่อแบบจำลองนั้นเรียบง่ายขึ้น การส่งออบเจ็กต์จากระยะไกลผ่านการทำให้เป็นอันดับจาวาจะทำให้ออบเจ็กต์ต้องเป็นแบบอนุกรมโดยไม่ต้องคำนึงถึงความซับซ้อนของมัน เห็นได้ชัดว่านี่ไม่ใช่กรณีการใช้งานของ OP
Robin

ฉันไม่ค่อยแน่ใจเกี่ยวกับการจำศีล แต่มีผู้ให้บริการ JPA รายอื่น ๆ ที่มีการดำเนินการที่ต้องการให้ผู้ให้บริการทำสำเนาของเอนทิตี (วัตถุ) Serializableอาจเป็นประโยชน์กับสิ่งนั้นและในบริบทของการคงอยู่ที่สอดคล้องกันมากกว่าCloneableเช่น
JimmyB

คำตอบนี้เป็นเพียงการถ่ายโอนข้อมูล แต่ก็ไม่ได้ช่วยให้ใครเข้าใจว่าทำไม
chrips

59

คุณต้องการเอนทิตีของคุณSerializableถ้าคุณต้องการโอนย้ายพวกเขาผ่านทางสาย (เป็นอันดับให้ตัวแทนอื่น ๆ ), จัดเก็บไว้ในเซสชัน http (ซึ่งต่อเนื่องเป็นอนุกรมไปยังฮาร์ดดิสก์โดยภาชนะ servlet) ฯลฯ

เพียงเพื่อความคงอยู่Serializableก็ไม่จำเป็นต้องใช้อย่างน้อยก็กับไฮเบอร์เนต Serializableแต่มันก็เป็นวิธีที่ดีที่สุดที่จะทำให้พวกเขา


2
ฉันไม่รู้บางทีองค์กรของฉันกำลังถูกโอนย้ายไปโดยปริยาย ฉันใช้ Hibernate + spring + jsf และ Tomcat สามารถใช้การถ่ายโอนโซ่ได้ที่ไหน
Roman

@ Roman ตัวอย่างเช่นผู้ใช้ปัจจุบัน (ซึ่งอาจเป็นเอนทิตี) และเอนทิตีที่เกี่ยวข้องทั้งหมดอาจสิ้นสุดในเซสชันซึ่ง Bozho กล่าวว่าสามารถจัดลำดับเป็นดิสก์โดยคอนเทนเนอร์ servlet
OrangeDog

นี่คือคำตอบที่ดีที่สุด "ทำไมและเมื่อไหร่"! ชัดเจน! ขอบคุณ
chrips

13

ตามเอกสารจำศีลในขณะที่ใช้คำอธิบายประกอบ @JoinColumn:

referencedColumnNameแต่ก็มีหนึ่งพารามิเตอร์เพิ่มเติมชื่อ พารามิเตอร์นี้ประกาศคอลัมน์ในเอนทิตีเป้าหมายที่จะใช้ในการเข้าร่วม หมายเหตุว่าเมื่อใช้ที่ไม่ใช่คอลัมน์คีย์หลักชั้นที่เกี่ยวข้องจะต้องมีการreferencedColumnNameSerializable


8

เพื่อเติมเต็มคำตอบที่ดีของ Conor ที่อ้างถึงข้อกำหนด JSR-317 โดยทั่วไปโครงการ EAR ประกอบด้วยโมดูล EJB ที่มี EJB เปิดเผยผ่านอินเตอร์เฟสระยะไกล ในกรณีนี้คุณต้องทำให้เอนทิตีถั่วของคุณสามารถทำให้เป็นอนุกรมได้เนื่องจากรวมอยู่ใน EJB ระยะไกลและสร้างขึ้นเพื่อเชื่อมต่อผ่านเครือข่าย

โครงการสงคราม JEE6 ที่ไม่มี CDI: สามารถมี EJB lite ซึ่งได้รับการสนับสนุนโดยเอนทิตี JPA ที่ไม่สามารถทำให้เป็นอนุกรมได้

โปรเจ็กต์ JEE6 สงครามกับ CDI: ถั่วที่ใช้เซสชันแอปพลิเคชันหรือขอบเขตการสนทนาต้องเป็นแบบอนุกรม แต่ถั่วที่ใช้ขอบเขตการร้องขอไม่จำเป็นต้องเป็นแบบอนุกรม ดังนั้นเอนทิตี JPA ที่แฝงอยู่ - ถ้ามี - จะเป็นไปตามความหมายเดียวกัน


7

ถ้าเราเพียงแค่พูดคุยเกี่ยวกับการติดตาSerializableไม่จำเป็น Serializableแต่มันเป็นวิธีที่ดีที่สุดที่จะทำให้หน่วยงาน

ถ้าเราจะเปิดเผยdomain/ entitiesวัตถุสัมผัสโดยตรงกับชั้นนำเสนอแทนการใช้ในกรณีที่เราจำเป็นต้องใช้DTO Serializableวัตถุโดเมนเหล่านี้สามารถเก็บไว้ในHTTPSessionการแคช / การเพิ่มประสิทธิภาพ http- เซสชั่นสามารถต่อเนื่องหรือคลัสเตอร์ และยังจำเป็นสำหรับการถ่ายโอนข้อมูลระหว่างJVMสาร

เมื่อเราใช้DTOเพื่อแยกชั้นการคงอยู่และเลเยอร์บริการทำเครื่องหมายวัตถุโดเมนว่าSerializableจะเป็นเคาน์เตอร์ที่มีประสิทธิผลและจะละเมิด " encapsulation" จากนั้นจะกลายเป็นรูปแบบการต่อต้าน

ตัวระบุคอมโพสิต

คลาสคีย์หลักจะต้องต่อเนื่องได้

โมเดล POJO

หากต้องการใช้อินสแตนซ์ของเอนทิตี้จากระยะไกลเป็นวัตถุเดี่ยวคลาสเอนทิตีต้องใช้Serializableอินเทอร์เฟซ

แคช
นอกจากนี้หากคุณกำลังดำเนินการclusteredระดับที่สองแล้วหน่วยงานของคุณจะต้องcache serializableตัวระบุต้องเป็นSerializableเพราะนั่นเป็นข้อกำหนด JPA เนื่องจากidentifierอาจใช้เป็นคีย์สำหรับรายการแคชระดับที่สอง

และเมื่อเราทำให้เป็นอันดับหน่วยงานตรวจสอบให้แน่ใจว่าจะให้ชัดเจน serialVersionUIDมีการปรับเปลี่ยนการเข้าถึงส่วนตัวเนื่องจากถ้าserializableคลาสไม่ได้ประกาศอย่างชัดเจนserialVersionUIDดังนั้นการรันไทม์ซีเรียลไลเซชันจะคำนวณค่าเริ่มต้นserialVersionUIDสำหรับคลาสนั้นตามแง่มุมต่าง ๆ ของคลาสดังอธิบายใน Java (TM) Object Serialization Specification serialVersionUIDการคำนวณเริ่มต้นนั้นมีความอ่อนไหวสูงต่อรายละเอียดของคลาสที่อาจแตกต่างกันไปขึ้นอยู่กับการใช้งานคอมไพเลอร์และอาจส่งผลให้เกิดการคาดไม่ถึงInvalidClassExceptionsระหว่างการดีซีเรียลไลเซชัน


6

ฉันเชื่อว่าปัญหาของคุณเกี่ยวข้องกับการมีฟิลด์ที่ซับซ้อน (คลาส) ซึ่งไม่มีคำอธิบายประกอบ ในกรณีเช่นนี้การจัดการเริ่มต้นจะถูกจัดเก็บวัตถุในรูปแบบต่อเนื่องในฐานข้อมูล (ซึ่งอาจไม่ใช่สิ่งที่คุณตั้งใจจะทำ) ตัวอย่าง:

Class CustomerData {
    int getAge();
    void setAge(int age);
}

@Entity
Class Customer {
  CustomerData getCustomerData();
  void setCustomerData(CustomerData data)
}

ในกรณีข้างต้น CustomerData จะถูกบันทึกในฟิลด์อาร์เรย์ไบต์ในฐานข้อมูลในรูปแบบที่ต่อเนื่องกัน


5

ข้อกำหนด JPA

ตามข้อกำหนด JPA องค์กรควรดำเนินการSerializableหากจำเป็นต้องส่งผ่านจาก JVM หนึ่งไปยังอีกเครื่องหนึ่งหรือถ้าเอนทิตีถูกใช้โดย Stateful Session Bean ซึ่งต้องผ่านการส่งผ่านคอนเทนเนอร์ EJB

หากต้องส่งอินสแตนซ์ของเอนทิตีโดยใช้ค่าเป็นวัตถุเดี่ยว (เช่นผ่านอินเทอร์เฟซระยะไกล) คลาสเอนทิตีจะต้องใช้Serializableอินเทอร์เฟซ

Hibernate

Hibernate ต้องการเพียงแค่แอททริบิวต์นั้นSerializableแต่ไม่ใช่เอนทิตีเอง

อย่างไรก็ตามการใช้ข้อกำหนด JPA ข้อกำหนด JPA ทั้งหมดที่เกี่ยวข้องกับSerializableเอนทิตีใช้กับไฮเบอร์เนตเช่นกัน

แมวตัวผู้

ตามTomcat documantation , HttpSessionแอตทริบิวต์ยังต้องเป็นSerializable:

เมื่อใดก็ตามที่ Apache Tomcat ปิดตัวลงตามปกติและเริ่มต้นใหม่หรือเมื่อมีการเรียกใช้แอปพลิเคชันโหลดใหม่การใช้งานตัวจัดการมาตรฐานจะพยายามซีเรียลไลซ์เซสชั่นที่ใช้งานอยู่ในปัจจุบันทั้งหมดไปยังไฟล์ดิสก์ เซสชั่นที่บันทึกไว้ทั้งหมดนั้นจะถูกดีซีเรียลไลซ์และเปิดใช้งาน (สมมติว่าพวกเขายังไม่หมดอายุในเวลาเฉลี่ย) เมื่อการรีโหลดแอปพลิเคชันเสร็จสมบูรณ์

เพื่อให้สามารถกู้คืนสถานะของแอ็ตทริบิวต์เซสชันได้สำเร็จแอ็ตทริบิวต์ดังกล่าวทั้งหมดต้องใช้อินเตอร์เฟส java.io.Serializable

ดังนั้นหากบุคคลหรือนิติบุคคลที่ถูกเก็บไว้ในก็ควรดำเนินการHttpSessionSerializable


4

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


3

โปรดดูhttp://www.adam-bien.com/roller/abien/entry/do_jpa_entities_have_to กล่าวว่าการดำเนินการของ java.io.Serializable นั้นจำเป็นสำหรับการถ่ายโอนข้อมูลผ่าน IIOP หรือ JRMP (RMI) ระหว่างอินสแตนซ์ JVM ในกรณีของเว็บแอพพลิเคชั่นบางครั้งวัตถุโดเมนจะถูกเก็บไว้ใน HTTPSession เพื่อวัตถุประสงค์ในการแคช / เพิ่มประสิทธิภาพ http- เซสชั่นสามารถต่อเนื่อง (พาสซีฟ) หรือคลัสเตอร์ ในทั้งสองกรณีเนื้อหาทั้งหมดจะต้องต่อเนื่องได้


1

การโจมตีจากระยะไกลโดยใช้บุรุษไปรษณีย์หรืออาแจ็กซ์หรือ js เชิงมุม ฯลฯ อาจทำให้เกิดวงจรการทำซ้ำด้วยข้อยกเว้น StackOverflow กับแจ็คสันเร็วขึ้น xml ดังนั้นมันจะดีกว่าถ้าใช้ serializer


1
  1. ในขณะใดที่จำเป็นต้องทำให้เอนทิตีของฉันเป็นอนุกรม?

การนำ ehcache ไปใช้กับ diskstore เป็นแคชระดับที่สอง (เช่นการใช้@Cacheableคำอธิบายประกอบบนเอนทิตีหรือวิธีการเก็บ / บริการ) ต้อง Serializable มิฉะนั้นแคชจะล้มเหลว ( NotSerializableException) เพื่อเขียนเอนทิตี้ไปยังดิสก์แคช


0

นี่เป็นข้อผิดพลาดที่เกิดขึ้นเมื่อคุณส่ง ID ที่พิมพ์ไม่ถูกต้องเป็นพารามิเตอร์ที่สองไปยังสิ่งที่ต้องการ em.find () (เช่นผ่านเอนทิตีเองแทนที่จะเป็น ID) ฉันยังไม่พบว่าจำเป็นต้องประกาศเอนทิตี JPA ให้ได้ - ไม่จำเป็นจริงๆเว้นแต่คุณจะใช้ referencedColumnName ตามที่อธิบายโดย aman


0

เมื่อเอนทิตี JPA ถูกใช้เป็นพารามิเตอร์หรือคืนค่าโดยการดำเนินการ EJB ระยะไกล

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