spring.jpa.open-in-view = คุณสมบัติที่แท้จริงใน Spring Boot คืออะไร?


121

ฉันเห็นspring.jpa.open-in-view=trueคุณสมบัติในเอกสาร Spring Boot สำหรับการกำหนดค่า JPA

  • เป็นtrueค่าเริ่มต้นสำหรับคุณสมบัตินี้หากไม่ได้ระบุไว้เลยหรือไม่;
  • สิ่งนี้ทำอะไรได้บ้าง? ฉันไม่พบคำอธิบายที่ดีสำหรับมัน
  • มันทำให้คุณใช้SessionFactoryแทนEntityManagerFactory? ถ้าใช่ฉันจะแจ้งให้ฉันใช้EntityManagerFactoryแทนได้อย่างไร

ขอบคุณ!

คำตอบ:


52

พร็อพเพอร์ตี้นี้จะลงทะเบียนOpenEntityManagerInViewInterceptorซึ่งลงทะเบียนEntityManagerกับเธรดปัจจุบันดังนั้นคุณจะมีเหมือนเดิมEntityManagerจนกว่าคำขอทางเว็บจะเสร็จสิ้น ไม่มีอะไรเกี่ยวข้องกับ Hibernate SessionFactoryเป็นต้น


ในขณะนี้ฉันมีตัวกรอง OpenEntityManagerInViewFilter เพื่อควบคุม EntityManager จนกว่าคำขอทางเว็บจะเสร็จสิ้น เครื่องดักฟังนี้ที่คุณหมายถึง "OpenEntityManagerInViewInterceptor" เหมือนกับ "OpenEntityManagerInViewFilter" หรือไม่ อะไรคือความแตกต่างระหว่างพวกเขา? ดังนั้นฉันจะไม่มีตัวกรองนี้อีกในบริบท servlet ของฉันสำหรับ Spring Boot?
Carlos Alberto

1
ตัวสกัดกั้นจะทำงานเฉพาะเมื่อคุณใช้ DispatcherServlet ใน Spring (เนื่องจากตัวสกัดกั้นเป็นกลไก Spring) ตัวกรองสามารถแมปกับ servlets ที่กำหนดค่าไว้ทั้งหมด (เราใช้สำหรับ FacesServlet ในหนึ่งในแอปพลิเคชันของเรา) ดังนั้นหากคุณใช้เฉพาะ DispatcherServlet คุณสามารถเพิ่มคุณสมบัติและลบตัวกรองหรือใช้ตัวกรอง
dunni

300

รูปแบบการต่อต้าน OSIV

แทนที่จะปล่อยให้เลเยอร์ธุรกิจตัดสินใจว่าจะดึงการเชื่อมโยงทั้งหมดที่ต้องการโดยเลเยอร์ View ได้อย่างไร OSIV (Open Session in View) จะบังคับให้ Persistence Context ยังคงเปิดอยู่เพื่อให้เลเยอร์ View สามารถทริกเกอร์การเริ่มต้นพร็อกซีได้ดังภาพประกอบ ตามแผนภาพต่อไปนี้

ใส่คำอธิบายภาพที่นี่

  • OpenSessionInViewFilterเรียกopenSessionวิธีการพื้นฐานและได้รับใหม่SessionFactorySession
  • ถูกผูกไว้กับSessionTransactionSynchronizationManager
  • การOpenSessionInViewFilterเรียกใช้doFilterการjavax.servlet.FilterChainอ้างอิงอ็อบเจ็กต์และคำร้องขอจะถูกประมวลผลเพิ่มเติม
  • DispatcherServletเรียกว่าและเส้นทางการร้องขอ HTTP PostControllerเพื่อพื้นฐาน
  • PostControllerเรียกPostServiceที่จะได้รับรายชื่อของPostหน่วยงาน
  • PostServiceเปิดรายการใหม่และHibernateTransactionManagerreuses เดียวกันที่ถูกเปิดออกโดยSessionOpenSessionInViewFilter
  • 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 ตรวจสอบบทความนี้


14
มีการบันทึกคำเตือนในปัจจุบัน
Vlad Mihalcea

สิ่งนี้ใช้ได้กับ Spring โดยทั่วไปหรือเฉพาะ Spring Boot เท่านั้น? สามารถปิดใช้งานผ่านคลาส @ Configuration-annotated แทนการตั้งค่าคุณสมบัติได้หรือไม่
Gordon

2
ใช้กับ Spring Boot เท่านั้น ใน Spring มาตรฐานคุณต้องเลือกอย่างชัดเจนว่าจะใช้ถั่วอะไรหรือต้องการตัวกรองเว็บเช่น OSIV ฉันไม่รู้ว่าคุณสามารถปิดการใช้งานผ่านคำอธิบายประกอบได้หรือไม่ ฉันรู้เฉพาะการตั้งค่าคอนฟิก
Vlad Mihalcea

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

5
ตามวิกิพีเดีย "รูปแบบการต่อต้านเป็นการตอบสนองทั่วไปสำหรับปัญหาที่เกิดขึ้นซ้ำซากซึ่งมักจะไม่ได้ผลและเสี่ยงต่อการต่อต้านอย่างมาก" นั่นคือสิ่งที่ Open Session in View คือ
Vlad Mihalcea
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.