การใช้ session.flush () ใน Hibernate คืออะไร


111

เมื่อเรากำลังอัปเดตบันทึกเราสามารถใช้session.flush()กับไฮเบอร์เนตได้ ต้องการflush()อะไร?

คำตอบ:


138

การล้างเซสชันจะบังคับให้ไฮเบอร์เนตซิงโครไนซ์สถานะในหน่วยความจำSessionกับฐานข้อมูล (กล่าวคือเพื่อเขียนการเปลี่ยนแปลงในฐานข้อมูล) โดยค่าเริ่มต้นไฮเบอร์เนตจะล้างการเปลี่ยนแปลงโดยอัตโนมัติสำหรับคุณ:

  • ก่อนการดำเนินการค้นหา
  • เมื่อมีการทำธุรกรรม

อนุญาตให้ล้างการSessionควบคุมที่ละเอียดกว่าอย่างชัดเจนที่อาจจำเป็นในบางสถานการณ์ (เพื่อรับ ID ที่กำหนดเพื่อควบคุมขนาดของเซสชัน ... )


8
โปรดทราบว่าคำตอบนี้อธิบายถึงพฤติกรรมไฮเบอร์เนตเริ่มต้น: พฤติกรรมการล้างสามารถเปลี่ยนแปลงได้ผ่านการตั้งค่าโหมดฟลัช รายละเอียดอยู่ในdocs.jboss.org/hibernate/orm/3.5/api/org/hibernate/… (เวอร์ชัน 3.5)
SteveT

1
ฉันพบเอกสารที่มันบอกว่าคุณกำลังพูดอะไรอยู่ แต่ฉันมีคำถามว่าลำดับความสำคัญคืออะไรสมมติว่า 1) ฉันมีคลาสที่ฉันกำลังบันทึกวัตถุโดยใช้รหัสid = session.save(obj);และมีการทำธุรกรรมในบรรทัดถัดไป แต่ obj ไม่ได้รับการบันทึก เป็น DB ทำไม? 2) ฉันบันทึก obj โดยใช้session.save(obj);กับการกระทำและในขณะที่ส่งคืนฉันใช้return obj.getprimaryID();ในกรณีนี้ obj จะถูกบันทึกลงใน DB เหตุใดพฤติกรรมนี้จึงเกิดขึ้น?
Amogh

74

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

นี่เหมือนกับการเปิด 2 เซสชันคำสั่ง SQL และการเปลี่ยนแปลงที่ทำใน 1 เซสชันจะไม่ปรากฏให้ผู้อื่นเห็นจนกว่าจะตกลง


12
ดี - การเปลี่ยนแปลงสามารถมองเห็นได้เล็กน้อย ตัวอย่างเช่นแถวที่ไม่ได้ผูกมัดสามารถสร้างการล็อกบนแถวที่แทรก แต่ไม่ถูกผูกมัดและหน่วงเวลาไม่ให้แถวเดียวกันถูกแทรกโดยเซสชันอื่นจนกว่าธุรกรรมจะถูกคอมมิตหรือย้อนกลับ มันจึงไม่สมบูรณ์มองไม่เห็น
rghome

2
ฉันท่องเว็บไปทั่วและนี่คือคำตอบที่ทำให้ฉันได้รับมันในที่สุด ขอบคุณ.
สิทธัตถะ

การใช้การใส่. flush () ในลูปคืออะไรแล้วถ้าคอมมิต () ทำการล้างในตอนท้าย?
Eildosa

@Kaushik Lele อะไรคือจุดล้าง () ถ้าไม่สามารถมองเห็นข้อมูลได้หลังจากล้าง? คุณสามารถอธิบายรายละเอียดเกี่ยวกับกรณีการใช้งานที่มีประโยชน์เพิ่มเติมได้หรือไม่?
java_geek

28

ฉันรู้แค่ว่าเมื่อเราเรียกsession.flush()คำสั่งของเราจะถูกดำเนินการในฐานข้อมูล แต่ไม่ได้กระทำ

สมมติว่าเราไม่ได้เรียกflush()ใช้ method บนวัตถุเซสชันและถ้าเราเรียกใช้วิธีการกระทำมันจะทำงานภายในของการเรียกใช้คำสั่งบนฐานข้อมูลจากนั้นจึงทำการคอมมิต

commit=flush+commit (ในกรณีที่ใช้งานได้)

ดังนั้นฉันจึงสรุปได้ว่าเมื่อเราเรียก method flush () บนวัตถุ Session มันจะไม่ได้รับการกระทำ แต่กระทบกับฐานข้อมูลและดำเนินการค้นหาและได้รับการย้อนกลับด้วย

ในการคอมมิตเราใช้คอมมิต () กับอ็อบเจกต์ธุรกรรม


คุณสามารถให้รายละเอียดบางอย่างเกี่ยวกับความจำเป็นในการล้าง?
java_geek

14

การล้างเซสชันจะทำให้ข้อมูลที่อยู่ในเซสชันซิงโครไนซ์กับข้อมูลที่อยู่ในฐานข้อมูล

เพิ่มเติมบนเว็บไซต์ Hibernate:

flush()จะเป็นประโยชน์เพราะมีอย่างค้ำประกันเกี่ยวกับเมื่อการประชุมดำเนินการ JDBC โทรเพียงเพื่อที่พวกเขาจะดำเนินการไม่ - flush()ยกเว้นคุณใช้


คุณสามารถระบุสถานการณ์ที่ผู้ใช้ควรกังวลเกี่ยวกับลำดับได้หรือไม่? การใช้ไฮเบอร์เนตคือการทำให้สิ่งที่เกี่ยวข้องกับ DB โปร่งใสต่อผู้ใช้ เมื่อเราทำการ "กระทำ" การล้างจะเกิดขึ้นโดยอัตโนมัติ สถานการณ์ที่คุณจะทำการล้าง แต่ไม่กระทำคืออะไร?
Kaushik Lele

1
@KaushikLele คุณสามารถอ้างถึงคำถามนี้ได้stackoverflow.com/questions/37382872/…
GMsoF

10

คุณอาจใช้flushเพื่อบังคับให้มีการรับรู้และตรวจพบข้อ จำกัด ในการตรวจสอบความถูกต้องในสถานที่ที่ทราบแทนที่จะเป็นเมื่อมีการทำธุรกรรม อาจเป็นไปได้ว่าcommitถูกเรียกโดยปริยายจากตรรกะของกรอบงานบางอย่างผ่านตรรกะที่เปิดเผยคอนเทนเนอร์หรือโดยเทมเพลต ในกรณีนี้ข้อยกเว้นใด ๆ ที่โยนไปอาจจับและจัดการได้ยาก (รหัสอาจสูงเกินไป)

ตัวอย่างเช่นหากคุณsave()สร้างออบเจ็กต์ EmailAddress ใหม่ซึ่งมีข้อ จำกัด เฉพาะในที่อยู่คุณจะไม่ได้รับข้อผิดพลาดจนกว่าคุณจะยอมรับ

การเรียกflush()บังคับให้แทรกแถวโดยจะโยน Exception หากมีการซ้ำกัน

อย่างไรก็ตามคุณจะต้องย้อนกลับเซสชันหลังจากข้อยกเว้น


4

ฉันต้องการเพียงแค่รวบรวมคำตอบทั้งหมดที่ให้ไว้ข้างต้นและเกี่ยวข้องกับวิธีการ Flush () กับ Session.save () เพื่อให้ความสำคัญมากขึ้น

Hibernate save () สามารถใช้เพื่อบันทึกเอนทิตีลงในฐานข้อมูล เราสามารถเรียกใช้วิธีนี้นอกธุรกรรมนั่นคือเหตุผลที่ฉันไม่ชอบวิธีนี้ในการบันทึกข้อมูล หากเราใช้สิ่งนี้โดยไม่มีธุรกรรมและเรามีการเรียงซ้อนระหว่างเอนทิตีระบบจะบันทึกเฉพาะเอนทิตีหลักเท่านั้นเว้นแต่เราจะล้างเซสชัน

flush (): บังคับให้เซสชันล้าง ใช้เพื่อซิงโครไนซ์ข้อมูลเซสชันกับฐานข้อมูล

เมื่อคุณเรียกใช้ session.flush () คำสั่งจะถูกดำเนินการในฐานข้อมูล แต่จะไม่ถูกคอมมิต ถ้าคุณไม่เรียก session.flush () และถ้าคุณเรียก session.commit () เมธอด Commit () ภายในจะรันคำสั่งและคอมมิต

ดังนั้นกระทำ () = ล้าง + กระทำ ดังนั้น session.flush () เพียงแค่รันคำสั่งในฐานข้อมูล (แต่ไม่คอมมิต) และคำสั่งจะไม่อยู่ในหน่วยความจำอีกต่อไป เพียงแค่บังคับให้เซสชันล้าง

ประเด็นสำคัญบางประการ:

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


3

flush() วิธีการทำให้เกิด Hibernate เพื่อล้างเซสชั่น คุณสามารถกำหนดค่าไฮเบอร์เนตเพื่อใช้โหมดล้างสำหรับเซสชันได้โดยใช้setFlushMode()วิธีการ หากต้องการรับโหมดล้างสำหรับเซสชันปัจจุบันคุณสามารถใช้getFlushMode()วิธีการ หากต้องการตรวจสอบว่าเซสชันสกปรกหรือไม่คุณสามารถใช้isDirty()วิธีการ โดยค่าเริ่มต้นไฮเบอร์เนตจะจัดการล้างเซสชัน

ตามที่ระบุไว้ในเอกสาร:

https://docs.jboss.org/hibernate/orm/5.2/userguide/html_single/chapters/flushing/Flushing.html

ฟลัชชิง

ฟลัชชิงเป็นกระบวนการซิงโครไนซ์สถานะของบริบทการคงอยู่กับฐานข้อมูลพื้นฐาน EntityManagerและ Hibernate Sessionเปิดเผยกำหนดวิธีการผ่านที่นักพัฒนาแอพลิเคชันสามารถเปลี่ยนรัฐถาวรของกิจการ

บริบทการคงอยู่ทำหน้าที่เป็นแคชการเขียนธุรกรรมโดยจัดคิวการเปลี่ยนแปลงสถานะเอนทิตีใด ๆ เช่นเดียวกับแคชการเขียนเบื้องหลังการเปลี่ยนแปลงจะถูกนำไปใช้ครั้งแรกในหน่วยความจำและซิงโครไนซ์กับฐานข้อมูลในช่วงเวลาล้าง การดำเนินการจะใช้เวลาล้างการเปลี่ยนแปลงทุกรัฐนิติบุคคลและแปลไปยังINSERT, UPDATEหรือDELETEคำสั่ง

กลยุทธ์การล้างจะกำหนดโดยโหมดฟลัชโหมดของเซสชันไฮเบอร์เนตที่ทำงานอยู่ในปัจจุบัน แม้ว่า JPA จะกำหนดกลยุทธ์การล้างเพียงสองแบบ ( AUTOและCOMMIT) แต่ Hibernate มีประเภทการล้างที่กว้างกว่ามาก:

  • ALWAYS: ล้างเซสชันก่อนการสืบค้นทุกครั้ง
  • AUTO: นี่เป็นโหมดเริ่มต้นและจะล้างเซสชันหากจำเป็นเท่านั้น
  • COMMIT: เซสชันพยายามชะลอการล้างจนกว่าจะมีการทำธุรกรรมปัจจุบันแม้ว่ามันอาจจะล้างก่อนเวลาอันควรด้วยก็ตาม
  • MANUAL: การล้างเซสชันถูกมอบหมายให้กับแอปพลิเคชันซึ่งต้องเรียกSession.flush()อย่างชัดเจนเพื่อใช้การเปลี่ยนแปลงบริบทการคงอยู่

โดยค่าเริ่มต้นไฮเบอร์เนตจะใช้AUTOโหมดฟลัชซึ่งทำให้เกิดการล้างในสถานการณ์ต่อไปนี้:

  • ก่อนที่จะทำธุรกรรม
  • ก่อนที่จะดำเนินการแบบสอบถาม JPQL / HQL ที่ทับซ้อนกับการดำเนินการของเอนทิตีที่อยู่ในคิว
  • ก่อนที่จะเรียกใช้แบบสอบถาม SQL ดั้งเดิมใด ๆ ที่ไม่มีการซิงโครไนซ์ที่ลงทะเบียน

1

โทรศัพท์EntityManager#flushจะมีผลข้างเคียง ใช้อย่างสะดวกสำหรับประเภทเอนทิตีที่มีค่า ID ที่สร้างขึ้น (ค่าลำดับ): ID ดังกล่าวจะใช้ได้เฉพาะเมื่อซิงโครไนซ์กับเลเยอร์การคงอยู่ หากจำเป็นต้องใช้รหัสนี้ก่อนที่ธุรกรรมปัจจุบันจะสิ้นสุดลง (เพื่อวัตถุประสงค์ในการบันทึกเป็นต้น) จำเป็นต้องล้างเซสชัน


0

ด้วยวิธีนี้คุณทำให้เกิดกระบวนการล้าง กระบวนการนี้ซิงโครไนซ์สถานะของฐานข้อมูลของคุณกับสถานะของเซสชันของคุณโดยการตรวจจับการเปลี่ยนแปลงสถานะและเรียกใช้คำสั่ง SQL ที่เกี่ยวข้อง

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