บทความนี้จะดำเนินการวิจัยเชิงลึกเกี่ยวกับการจัดการธุรกรรมของฤดูใบไม้ผลิ ส่วนใหญ่แนะนำวิธีการทำงาน @Transactional ที่ด้านล่าง บทความต่อไปนี้จะแนะนำ:
การใช้แอตทริบิวต์เช่นการแพร่กระจาย (การแพร่กระจายธุรกรรม) และการแยก (แยก)
ข้อผิดพลาดของการใช้ธุรกรรมคืออะไรและจะหลีกเลี่ยงได้อย่างไร
JPA และการจัดการธุรกรรม
เป็นสิ่งสำคัญที่ JPA เองไม่ได้ให้การจัดการธุรกรรมที่ประกาศใด ๆ หากคุณใช้ JPA นอกคอนเทนเนอร์ฉีดพึ่งพาการทำธุรกรรมจะต้องดำเนินการโดยนักพัฒนาโดยนักพัฒนา
userTransAction utx = entityManager.getTransaction (); ลอง {utx.begin (); BusinessLogic (); utx.Commit ();} catch (Exception Ex) {utx.rollback (); throlex;}}วิธีการจัดการธุรกรรมนี้ช่วยให้สามารถแสดงขอบเขตการทำธุรกรรมได้อย่างชัดเจนในรหัส แต่มีข้อเสียดังต่อไปนี้:
รหัสและข้อผิดพลาดซ้ำ ๆ มีแนวโน้มที่จะ
ข้อผิดพลาดใด ๆ อาจมีผลกระทบมากขึ้น
ข้อผิดพลาดเป็นเรื่องยากที่จะแก้ไขข้อบกพร่องและทำซ้ำ
ลดความสามารถในการอ่านของฐานรหัส
จะเกิดอะไรขึ้นถ้าวิธีการเรียกวิธีการทำธุรกรรมอื่น ๆ ?
ใช้ Spring @Transactional
การใช้ Spring @Transactional รหัสด้านบนจะง่ายขึ้นเป็น:
@Transactional PublicVoid BusinessLogic () {... ใช้ Entity Manager ภายในธุรกรรม ... }รหัสมีความกระชับและอ่านได้มากขึ้นและเป็นวิธีที่แนะนำในการจัดการในฤดูใบไม้ผลิในปัจจุบัน
ประเด็นสำคัญมากมายเช่นการแพร่กระจายธุรกรรมสามารถจัดการได้โดยอัตโนมัติโดยใช้ @Transactional ในกรณีนี้หาก BusinessLogic () เรียกวิธีการทำธุรกรรมอื่นวิธีการจะกำหนดวิธีการเข้าร่วมการทำธุรกรรมตามตัวเลือก
ข้อเสียเปรียบอย่างหนึ่งของกลไกที่ทรงพลังนี้คือมันซ่อนการดำเนินการพื้นฐานและยากที่จะแก้ไขข้อบกพร่องเมื่อมันทำงานไม่ถูกต้อง
@ความหมายของ transactional
หนึ่งในประเด็นสำคัญเกี่ยวกับ @Transactional คือการพิจารณาสองแนวคิดแยกกันซึ่งทั้งคู่มีขอบเขตและวงจรชีวิตของตัวเอง:
บริบทการคงอยู่ (บริบทการคงอยู่)
ธุรกรรมฐานข้อมูล
@Transactional ตัวเองกำหนดขอบเขตของการทำธุรกรรมเดียว การทำธุรกรรมนี้อยู่ในขอบเขตของบริบทการคงอยู่
บริบทการคงอยู่ใน JPA คือ EntityManager และการใช้งานภายในใช้เซสชันไฮเบอร์เนต (โดยใช้ไฮเบอร์เนตเป็นผู้ให้บริการการคงอยู่)
บริบทการคงอยู่เป็นเพียงวัตถุแบบซิงโครนัสที่บันทึกสถานะของวัตถุ Java ของคอลเลกชัน จำกัด และทำให้มั่นใจได้ว่าการเปลี่ยนแปลงในวัตถุเหล่านี้จะยังคงอยู่ในฐานข้อมูลในที่สุด
นี่เป็นแนวคิดที่แตกต่างกันมากจากการทำธุรกรรมเดียว ตัวจัดการเอนทิตีสามารถใช้ในการทำธุรกรรมหลายรายการและใช้อย่างแท้จริงในลักษณะนี้
EntityManager ครอบคลุมการทำธุรกรรมหลายรายการเมื่อใด
สถานการณ์ที่พบบ่อยที่สุดคือเมื่อแอปพลิเคชันใช้เซสชันเปิดในโหมดมุมมองเพื่อจัดการข้อยกเว้นการเริ่มต้นที่ขี้เกียจ บทความก่อนหน้านี้ได้แนะนำข้อดีและข้อเสียของวิธีการนี้
ในกรณีนี้การสืบค้นหลายรายการที่ดำเนินการโดยเลเยอร์มุมมองอยู่ในการทำธุรกรรมแยกต่างหากแทนที่จะเป็นตรรกะธุรกิจธุรกรรมเดี่ยว แต่การสืบค้นเหล่านี้ได้รับการจัดการโดยตัวจัดการเอนทิตีเดียวกัน
อีกสถานการณ์หนึ่งคือนักพัฒนาทำเครื่องหมายบริบทการคงอยู่เป็น PersistenceContextType.extended ซึ่งหมายความว่าสามารถตอบสนองต่อการร้องขอหลายครั้ง
จะกำหนดความสัมพันธ์ระหว่าง EntityManager และธุรกรรมได้อย่างไร?
สิ่งนี้ถูกเลือกโดยนักพัฒนาแอปพลิเคชัน แต่วิธีที่พบบ่อยที่สุดสำหรับ JPA Entity Manager คือโหมด "Entity Manager ต่อการทำธุรกรรมแอปพลิเคชัน" วิธีการทั่วไปของการฉีดผู้จัดการเอนทิตีคือ:
@persistenceContext PrivateentityManager em;
ค่าเริ่มต้นคือโหมด "Entity Manager ต่อการทำธุรกรรม" ในโหมดนี้หากใช้ตัวจัดการเอนทิตีภายในวิธี @Transactional วิธีการจะทำงานในการทำธุรกรรมเดียว
@persistenceContext ทำงานอย่างไร
คำถามที่ตามมาคือวิธีที่ @persistenceContext สามารถฉีด Entity Manager ได้เฉพาะเมื่อคอนเทนเนอร์เริ่มต้นโดยสมมติว่าวงจรชีวิตของ Entity Manager นั้นสั้นและต้องมีผู้จัดการเอนทิตีหลายตัวต่อคำขอ
คำตอบคือมันไม่สามารถ: EntityManager เป็นอินเทอร์เฟซและสิ่งที่ถูกฉีดเข้าไปในถั่วฤดูใบไม้ผลิไม่ใช่ตัวจัดการเอนทิตี แต่บริบทรับรู้พร็อกซี (พร็อกซีรับรู้บริบท) ของผู้จัดการเอนทิตีเฉพาะในรันไทม์
คลาสเฉพาะที่ใช้กันทั่วไปสำหรับพร็อกซีคือ SharedEntityManagerInvocationHandler ซึ่งสามารถยืนยันได้ด้วยความช่วยเหลือของดีบักเกอร์
แล้ว @transactional ทำงานอย่างไร?
พร็อกซีบริบทถาวรที่ใช้อินเทอร์เฟซ EntityManager ไม่ได้เป็นเพียงส่วนหนึ่งของการจัดการธุรกรรมที่เปิดเผย แต่จริงๆแล้วมีสามองค์ประกอบ:
พร็อกซี EntityManager เอง
ส่วนของธุรกรรม
ผู้จัดการธุรกรรม
ลองดูที่สามส่วนและการโต้ตอบของพวกเขา
ส่วนของธุรกรรม
ส่วนการทำธุรกรรมเป็นส่วน "รอบ" ที่สามารถเรียกได้ก่อนและหลังวิธีธุรกิจที่มีคำอธิบายประกอบ คลาสเฉพาะที่ใช้ส่วนคือ TransactionInterceptor
มีความรับผิดชอบหลักสองประการในส่วนของการทำธุรกรรม:
ใน 'ก่อน' ส่วนจะให้จุดโทรเพื่อตัดสินใจว่าวิธีการที่เรียกว่าธุรกิจควรทำงานภายในขอบเขตของการทำธุรกรรมอย่างต่อเนื่องหรือเริ่มการทำธุรกรรมอิสระใหม่หรือไม่
ใน 'After' ส่วนจำเป็นต้องพิจารณาว่าการทำธุรกรรมนั้นเกิดขึ้นย้อนกลับหรือดำเนินการต่อไป
ใน 'ก่อน' ส่วนการทำธุรกรรมนั้นไม่มีตรรกะการตัดสินใจใด ๆ และการตัดสินใจเริ่มการทำธุรกรรมใหม่จะถูกมอบหมายให้ผู้จัดการธุรกรรมเพื่อให้เสร็จสิ้น
ผู้จัดการธุรกรรม
ผู้จัดการธุรกรรมจำเป็นต้องแก้ปัญหาสองข้อต่อไปนี้:
ควรสร้างตัวจัดการเอนทิตีใหม่หรือไม่?
ควรเริ่มทำธุรกรรมใหม่หรือไม่?
สิ่งเหล่านี้ต้องการส่วนการทำธุรกรรมที่จะพิจารณาเมื่อมีการเรียกตรรกะ 'ก่อน' การตัดสินใจของผู้จัดการธุรกรรมจะขึ้นอยู่กับสองจุดต่อไปนี้:
การทำธุรกรรมเกิดขึ้นหรือไม่
คุณสมบัติการแพร่กระจายของวิธีการทำธุรกรรม (ตัวอย่างเช่นต้องการ _New จะเริ่มการทำธุรกรรมใหม่เสมอ)
หากผู้จัดการธุรกรรมกำหนดว่าคุณต้องการสร้างธุรกรรมใหม่จะ:
1. สร้างตัวจัดการเอนทิตีใหม่
2. ตัวจัดการ intity ถูกผูกไว้กับเธรดปัจจุบัน
3. รับการเชื่อมต่อจากพูลเชื่อมต่อฐานข้อมูล
4. ผูกการเชื่อมต่อกับเธรดปัจจุบัน
ใช้ตัวแปร ThreadLocal เพื่อผูกทั้ง Entity Manager และการเชื่อมต่อฐานข้อมูลกับเธรดปัจจุบัน
การทำธุรกรรมจะทำงานเมื่อเก็บไว้ในเธรดและเมื่อไม่ได้ใช้งานอีกต่อไปผู้จัดการธุรกรรมจะตัดสินใจว่าจะล้างพวกเขาหรือไม่
ส่วนใดส่วนหนึ่งของโปรแกรมสามารถเรียกคืนได้จากเธรดหากจำเป็นต้องมีการเชื่อมต่อ Entity Manager และฐานข้อมูล
พร็อกซี EntityManager
พร็อกซี EntityManager (แนะนำก่อนหน้านี้) เป็นส่วนสุดท้ายของปริศนา เมื่อวิธีการทางธุรกิจเรียก EntityManager.persist () สิ่งนี้จะไม่ถูกเรียกโดยตรงโดย Entity Manager
แต่วิธีการทางธุรกิจเรียกตัวแทนซึ่งได้รับตัวจัดการเอนทิตีปัจจุบันจากเธรด ดังที่ได้กล่าวไว้ก่อนหน้านี้ผู้จัดการธุรกรรมจะเชื่อมโยงตัวจัดการเอนทิตีกับเธรด
หลังจากทำความเข้าใจกับส่วนต่าง ๆ ของกลไก @Transactional มาดูการกำหนดค่าสปริงที่ใช้กันทั่วไปที่ใช้กันอยู่
รวมสามส่วน
จะรวมสามส่วนเพื่อให้คำอธิบายประกอบการทำธุรกรรมสามารถทำงานได้อย่างถูกต้อง? ก่อนกำหนดโรงงาน Entity Manager
สิ่งนี้ช่วยให้คุณสามารถฉีดพร็อกซีเอนทิตีด้วยคำอธิบายประกอบบริบทการคงอยู่
@Configuration PublicClass EntityManagerFactoryConfiguration {@Autowired PrivatedAtAsource DataSource; @Bean (ชื่อ = "EntityManagerFactory") PublicLocalContainerentityManageFactoryBean emf () NewString [] {"Your.package"}); emf.setjpavendoradapter (newhibernatejpavendoradapter ()); returnemf;}}}ขั้นตอนต่อไปคือการกำหนดค่าตัวจัดการธุรกรรมและใช้แง่มุมการทำธุรกรรมในชั้นเรียน @Transactional
@Configuration @EnableTransactionManagement PublicClass TransactionManagersConfig {@autowired EntityManagerFactory EMF; @Autowired PrivatedAtAsource DataSource; @Bean (name = "TransactionManager" newjpatransactionManager (); tm.setentityManagerFactory (EMF); tm.setDataSource (DataSource); returnm;}}}คำอธิบายประกอบ @EnableTransactionManagement แจ้งให้ทราบว่าฤดูใบไม้ผลิว่าชั้นเรียนมีคำอธิบายประกอบโดย @Transactional ถูกล้อมรอบด้วยการตัดของธุรกรรม วิธีนี้สามารถใช้ @Transactional
สรุป
กลไกการจัดการธุรกรรมที่ประกาศของฤดูใบไม้ผลินั้นทรงพลังมาก แต่สามารถนำไปใช้ในทางที่ผิดหรือกำหนดค่าได้อย่างง่ายดาย
เมื่อปัญหาเช่นกลไกนี้ทำงานไม่ถูกต้องหรือล้มเหลวในการบรรลุผลการดำเนินงานที่คาดหวังจะเป็นประโยชน์ในการทำความเข้าใจการทำงานภายใน
สิ่งที่สำคัญที่สุดที่ต้องจดจำคือการคำนึงถึงสองแนวคิด: การทำธุรกรรมและบริบทการคงอยู่แต่ละอันมีวงจรชีวิตที่ชัดเจนของตัวเองซึ่งไม่สามารถอ่านได้
ข้างต้นเป็นเนื้อหาทั้งหมดของบทความนี้เกี่ยวกับหลักการทำงานของฤดูใบไม้ผลิ @Transactional ฉันหวังว่ามันจะเป็นประโยชน์กับทุกคน เพื่อนที่สนใจสามารถอ้างถึงหัวข้ออื่น ๆ ที่เกี่ยวข้องในเว็บไซต์นี้ต่อไป หากมีข้อบกพร่องใด ๆ โปรดฝากข้อความไว้เพื่อชี้ให้เห็น ขอบคุณเพื่อนที่ให้การสนับสนุนเว็บไซต์นี้!