การใช้ flush () อย่างถูกต้องใน JPA / Hibernate


111

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

ตอนนี้ฉันได้ติดตามสถานการณ์ที่มีสองเอนทิตีAและB(ในความสัมพันธ์แบบหนึ่งต่อหนึ่ง แต่ไม่ได้บังคับใช้หรือจำลองโดย JPA) Aมี PK recordIdคอมโพสิตซึ่งตั้งด้วยตนเองและยังมีสนาม นี้recordIdควรจะเขียนกิจการเป็นต่างประเทศที่สำคัญในการB AฉันกำลังบันทึกAและBในการทำธุรกรรมครั้งเดียว ปัญหาคือว่าค่าสร้างขึ้นโดยอัตโนมัติA.recordIdไม่ได้มีอยู่ในการทำธุรกรรมจนกว่าฉันโทรชัดเจนem.flush()หลังจากเรียกบนem.persist() A(ถ้าฉันมี IDENTITY PK ที่สร้างขึ้นโดยอัตโนมัติค่าจะได้รับการอัปเดตโดยตรงในเอนทิตี แต่นั่นไม่ใช่กรณีนี้)

อาจem.flush()ก่อให้เกิดอันตรายใด ๆ เมื่อใช้ภายในธุรกรรมหรือไม่?

คำตอบ:


150

อาจเป็นรายละเอียดที่แน่นอนem.flush()ขึ้นอยู่กับการใช้งาน โดยทั่วไปแล้วผู้ให้บริการ JPA เช่น Hibernate สามารถแคชคำแนะนำ SQL ที่ควรส่งไปยังฐานข้อมูลได้บ่อยครั้งจนกว่าคุณจะทำธุรกรรมจริง ตัวอย่างเช่นคุณโทรem.persist()ไปไฮเบอร์เนตจำได้ว่าต้องสร้างฐานข้อมูล INSERT แต่จะไม่ดำเนินการตามคำสั่งจนกว่าคุณจะทำธุรกรรม Afaik ส่วนใหญ่ทำด้วยเหตุผลด้านประสิทธิภาพ

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

สิ่งที่em.flush()ต้องทำคือการล้างแคชคำสั่ง SQL ภายในและดำเนินการกับฐานข้อมูลทันที

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


1
เขาพูดอะไร. em.flush () พฤติกรรมสะท้อน java.io.Flushable.flush () ซึ่งข้อมูลที่บัฟเฟอร์ทั้งหมดจะถูกส่งไปยังปลายทางที่เหมาะสม
Erik

4
ถ้า flush () ส่งข้อมูลไปยังฐานข้อมูล? จะเกิดอะไรขึ้นหากเกิดข้อยกเว้นหลังจากนั้น? ผู้จัดการนิติบุคคลจะย้อนกลับทุกอย่างหรือไม่ แม้แต่ข้อมูลที่เขียนในการล้างครั้งแรก?
Jaime Hablutzel

101
flush () ส่งคำสั่ง SQL ไปยังฐานข้อมูลเช่น INSERT, UPDATE เป็นต้นซึ่งจะไม่ส่ง COMMIT ดังนั้นหากคุณมีข้อยกเว้นหลังจาก flush () คุณยังสามารถย้อนกลับได้อย่างสมบูรณ์
Flavio

17
คุณสามารถย้อนกลับ DB ได้ แต่จะไม่ย้อนกลับการเปลี่ยนแปลงใด ๆ กับอ็อบเจ็กต์เช่น 'เวอร์ชัน' ที่เพิ่มขึ้นอัตโนมัติ ID ที่สร้างขึ้นโดยอัตโนมัติเป็นต้นนอกจากนี้ตัวจัดการเอนทิตีจะถูกปิดหลังจากการย้อนกลับ เพียงระวังว่าหากคุณพยายาม 'ผสาน' วัตถุกับเซสชันอื่น 'เวอร์ชัน' ที่เพิ่มขึ้นอัตโนมัติโดยเฉพาะอาจทำให้เกิด OptimisticLockException
Peter Davis

11
นอกเหนือจากการกระตุ้นให้เกิดผลข้างเคียงแล้วอีกเหตุผลหนึ่งที่ต้องใช้ flush () คือหากคุณต้องการอ่านผลของการดำเนินการในฐานข้อมูลโดยใช้ JPQL / HQL (เช่นในการทดสอบ) JPA ไม่สามารถใช้ข้อมูลแคชเมื่อดำเนินการค้นหาเหล่านี้ดังนั้นจะอ่านเฉพาะสิ่งที่อยู่ในฐานข้อมูลเท่านั้น
sleske

2

ที่จริงem.flush()ทำมากกว่าแค่ส่งคำสั่ง SQL ที่แคชไว้ พยายามซิงโครไนซ์บริบทการคงอยู่กับฐานข้อมูลพื้นฐาน อาจทำให้ใช้เวลามากในกระบวนการของคุณหากแคชของคุณมีคอลเล็กชันที่จะซิงโครไนซ์

ข้อควรระวังในการใช้งาน


2

em.flush () สามารถก่อให้เกิดอันตรายใด ๆ เมื่อใช้ภายในธุรกรรมได้หรือไม่?

ใช่อาจมีการล็อกฐานข้อมูลเป็นเวลานานเกินความจำเป็น

โดยทั่วไปเมื่อใช้ JPA คุณจะมอบหมายการจัดการธุรกรรมให้กับคอนเทนเนอร์ (หรือที่เรียกว่า CMT - โดยใช้คำอธิบายประกอบ @Transactional เกี่ยวกับวิธีการทางธุรกิจ) ซึ่งหมายความว่าธุรกรรมจะเริ่มต้นโดยอัตโนมัติเมื่อเข้าสู่วิธีการและยอมรับ / ย้อนกลับในตอนท้าย หากคุณปล่อยให้ EntityManager จัดการกับการซิงโครไนซ์ฐานข้อมูลการดำเนินการคำสั่ง sql จะถูกทริกเกอร์ก่อนการคอมมิตเท่านั้นซึ่งนำไปสู่การล็อกฐานข้อมูลที่มีอายุสั้น มิฉะนั้นการดำเนินการเขียนแบบล้างด้วยตนเองของคุณอาจเก็บล็อกระหว่างการล้างด้วยมือและการคอมมิตอัตโนมัติซึ่งอาจยาวนานตามเวลาดำเนินการของวิธีการที่เหลืออยู่

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

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