รูปแบบการต่อต้าน OSIV
แทนที่จะปล่อยให้เลเยอร์ธุรกิจตัดสินใจว่าจะดึงการเชื่อมโยงทั้งหมดที่ต้องการโดยเลเยอร์ View ได้อย่างไร OSIV (Open Session in View) จะบังคับให้ Persistence Context ยังคงเปิดอยู่เพื่อให้เลเยอร์ View สามารถทริกเกอร์การเริ่มต้นพร็อกซีได้ดังภาพประกอบ ตามแผนภาพต่อไปนี้
OpenSessionInViewFilter
เรียกopenSession
วิธีการพื้นฐานและได้รับใหม่SessionFactory
Session
- ถูกผูกไว้กับ
Session
TransactionSynchronizationManager
- การ
OpenSessionInViewFilter
เรียกใช้doFilter
การjavax.servlet.FilterChain
อ้างอิงอ็อบเจ็กต์และคำร้องขอจะถูกประมวลผลเพิ่มเติม
DispatcherServlet
เรียกว่าและเส้นทางการร้องขอ HTTP PostController
เพื่อพื้นฐาน
PostController
เรียกPostService
ที่จะได้รับรายชื่อของPost
หน่วยงาน
PostService
เปิดรายการใหม่และHibernateTransactionManager
reuses เดียวกันที่ถูกเปิดออกโดยSession
OpenSessionInViewFilter
PostDAO
เรียกรายชื่อของPost
หน่วยงานโดยไม่ต้องเริ่มต้นการเชื่อมโยงใด ๆ ขี้เกียจ
PostService
กระทำธุรกรรมพื้นฐาน แต่Session
ไม่ได้ปิดเพราะมันถูกเปิดออกภายนอก
- การ
DispatcherServlet
เริ่มต้นการแสดงผล UI ซึ่งในทางกลับกันจะนำทางการเชื่อมโยงแบบ lazy และทริกเกอร์การเริ่มต้น
OpenSessionInViewFilter
สามารถปิดSession
และเชื่อมต่อฐานข้อมูลพื้นฐานจะถูกปล่อยออกเช่นกัน
เมื่อมองแวบแรกสิ่งนี้อาจดูเหมือนไม่ใช่เรื่องน่ากลัวที่ต้องทำ แต่เมื่อคุณดูจากมุมมองของฐานข้อมูลข้อบกพร่องต่างๆจะเริ่มชัดเจนขึ้น
ชั้นบริการเปิดและปิดธุรกรรมฐานข้อมูล แต่หลังจากนั้นไม่มีธุรกรรมที่ชัดเจนเกิดขึ้น ด้วยเหตุนี้ทุกคำสั่งเพิ่มเติมที่ออกจากเฟสการเรนเดอร์ UI จะถูกดำเนินการในโหมดการคอมมิตอัตโนมัติ การคอมมิตอัตโนมัติจะสร้างแรงกดดันให้กับเซิร์ฟเวอร์ฐานข้อมูลเนื่องจากแต่ละคำสั่งต้องล้างบันทึกธุรกรรมลงในดิสก์ดังนั้นจึงทำให้มีการรับส่งข้อมูล I / O จำนวนมากที่ฝั่งฐานข้อมูล การเพิ่มประสิทธิภาพอย่างหนึ่งคือการทำเครื่องหมายConnection
ว่าอ่านอย่างเดียวซึ่งจะช่วยให้เซิร์ฟเวอร์ฐานข้อมูลหลีกเลี่ยงการเขียนลงในบันทึกธุรกรรม
ไม่มีการแยกข้อกังวลอีกต่อไปเนื่องจากคำสั่งถูกสร้างขึ้นโดยชั้นบริการและโดยกระบวนการแสดงผล UI การเขียนการทดสอบการรวมที่ยืนยันจำนวนคำสั่งที่สร้างขึ้นจะต้องดำเนินการผ่านทุกชั้น (เว็บบริการ DAO) ในขณะที่มีการปรับใช้แอปพลิเคชันบนเว็บคอนเทนเนอร์ แม้ว่าจะใช้ฐานข้อมูลในหน่วยความจำ (เช่น HSQLDB) และเว็บเซิร์ฟเวอร์ที่มีน้ำหนักเบา (เช่น Jetty) การทดสอบการรวมเหล่านี้จะดำเนินการได้ช้ากว่าการแยกชั้นและการทดสอบการรวมส่วนหลังจะใช้ฐานข้อมูลในขณะที่ การทดสอบการรวมส่วนหน้ากำลังจำลองชั้นบริการโดยสิ้นเชิง
เลเยอร์ UI จำกัด เฉพาะการนำทางที่เชื่อมโยงซึ่งสามารถทำให้เกิดปัญหาการสืบค้น N + 1 ได้ในทางกลับกัน แม้ว่าไฮเบอร์เนตจะมีข้อเสนอ@BatchSize
สำหรับการดึงการเชื่อมโยงเป็นกลุ่มและFetchMode.SUBSELECT
เพื่อรับมือกับสถานการณ์นี้คำอธิบายประกอบจะส่งผลต่อแผนการดึงข้อมูลเริ่มต้นดังนั้นจึงนำไปใช้กับทุกกรณีการใช้งานทางธุรกิจ ด้วยเหตุนี้แบบสอบถามชั้นการเข้าถึงข้อมูลจึงเหมาะสมกว่ามากเนื่องจากสามารถปรับให้เข้ากับข้อกำหนดในการดึงข้อมูลกรณีการใช้งานปัจจุบันได้
สุดท้าย แต่ไม่ท้ายสุดการเชื่อมต่อฐานข้อมูลจะถูกระงับตลอดระยะการแสดงผล UI ซึ่งจะเพิ่มเวลาเช่าการเชื่อมต่อและ จำกัด ปริมาณงานธุรกรรมโดยรวมเนื่องจากความแออัดในพูลการเชื่อมต่อฐานข้อมูล ยิ่งมีการเชื่อมต่อมากขึ้นคำขออื่น ๆ ที่พร้อมกันจะต้องรอรับการเชื่อมต่อจากพูลมากขึ้น
Spring Boot และ OSIV
แต่น่าเสียดายที่OSIV (เปิดเซสชันใน View) ถูกเปิดใช้งานโดยเริ่มต้นในฤดูใบไม้ผลิ Bootและ OSIV มันเป็นความคิดที่ไม่ดีจากประสิทธิภาพและ scalability มุมมอง
ดังนั้นตรวจสอบให้แน่ใจว่าในapplication.properties
ไฟล์กำหนดค่าคุณมีรายการต่อไปนี้:
spring.jpa.open-in-view=false
นี้จะปิดการใช้งาน OSIV เพื่อให้คุณสามารถจัดการกับLazyInitializationException
วิธีการที่เหมาะสม
ตั้งแต่เวอร์ชัน 2.0 Spring Boot จะออกคำเตือนเมื่อเปิดใช้งานOSIVตามค่าเริ่มต้นดังนั้นคุณจะพบปัญหานี้ได้นานก่อนที่จะส่งผลกระทบต่อระบบการใช้งานจริง
สำหรับรายละเอียดเพิ่มเติมเกี่ยวกับ OSIV ตรวจสอบบทความนี้