1. หลักการพื้นฐานของการทำธุรกรรม
สาระสำคัญของการทำธุรกรรมสปริงคือการสนับสนุนของฐานข้อมูลสำหรับการทำธุรกรรม หากไม่มีการสนับสนุนการทำธุรกรรมฐานข้อมูลสปริงไม่สามารถให้ฟังก์ชั่นการทำธุรกรรมได้ สำหรับฐานข้อมูลการทำงานของ JDBC บริสุทธิ์หากคุณต้องการใช้ธุรกรรมคุณสามารถทำตามขั้นตอนต่อไปนี้:
1. รับการเชื่อมต่อการเชื่อมต่อ con = drivermanager.getConnection ()
2. เปิดธุรกรรม con.setautocommit (จริง/เท็จ);
3. ดำเนินการ crud
4. การทำธุรกรรม / การทำธุรกรรมย้อนกลับ con.Commit () / con.rollback ();
5. ปิดการเชื่อมต่อ conn.close ();
หลังจากใช้ฟังก์ชั่นการจัดการธุรกรรมของฤดูใบไม้ผลิเราไม่สามารถเขียนรหัสในขั้นตอนที่ 2 และ 4 ได้อีกต่อไป แต่จะทำโดยอัตโนมัติโดย Spirng ดังนั้นสปริงจะเปิดและปิดธุรกรรมก่อนและหลังการเขียนที่เราเขียนได้อย่างไร? ด้วยการแก้ปัญหานี้เราสามารถเข้าใจหลักการการดำเนินงานของการจัดการธุรกรรมของฤดูใบไม้ผลิจากทั้งหมด ให้ฉันแนะนำวิธีการอธิบายประกอบเป็นตัวอย่างสั้น ๆ
1. เปิดไดรเวอร์คำอธิบายประกอบในไฟล์การกำหนดค่าและระบุโดยหมายเหตุประกอบ @Transactional ในคลาสและวิธีการที่เกี่ยวข้อง
2. เมื่อฤดูใบไม้ผลิเริ่มต้นมันจะแยกวิเคราะห์และสร้างถั่วที่เกี่ยวข้อง ในเวลานี้มันจะตรวจสอบคลาสและวิธีการที่มีคำอธิบายประกอบที่เกี่ยวข้องและสร้างพร็อกซีสำหรับคลาสและวิธีการเหล่านี้และทำการฉีดการกำหนดค่าที่เกี่ยวข้องตามพารามิเตอร์ที่เกี่ยวข้องของ @TransAction เพื่อให้การทำธุรกรรมที่เกี่ยวข้องถูกประมวลผลสำหรับเราในพร็อกซี
3. การทำธุรกรรมการกระทำและการย้อนกลับของเลเยอร์ฐานข้อมูลจริงจะถูกนำไปใช้ผ่าน binlog หรือบันทึกการทำซ้ำ
2. คุณสมบัติการแพร่กระจายของธุรกรรมฤดูใบไม้ผลิ
แอตทริบิวต์การแพร่กระจายที่เรียกว่าการทำธุรกรรมสปริงกำหนดว่าฤดูใบไม้ผลิควรจัดการกับพฤติกรรมของการทำธุรกรรมหลายรายการเมื่อมีอยู่ในเวลาเดียวกัน คุณสมบัติเหล่านี้ถูกกำหนดไว้ในการทำธุรกรรม ค่าคงที่เฉพาะมีการอธิบายในตารางต่อไปนี้:
iii. ระดับการแยกฐานข้อมูล
Dirty Reading: หนึ่งธุรกรรมเพิ่มลบและแก้ไขข้อมูล แต่ไม่ได้กระทำและธุรกรรมอื่นสามารถอ่านข้อมูลที่ไม่มีข้อผูกมัดได้ หากการทำธุรกรรมครั้งแรกย้อนกลับไปในเวลานี้ธุรกรรมที่สองจะอ่านข้อมูลสกปรก
ไม่มีการอ่านซ้ำ ๆ : การดำเนินการอ่านสองครั้งเกิดขึ้นในการทำธุรกรรมเดียว ระหว่างการดำเนินการอ่านครั้งแรกและการดำเนินการที่สองธุรกรรมอื่น ๆ จะปรับเปลี่ยนข้อมูล ในเวลานี้ข้อมูลที่อ่านสองครั้งไม่สอดคล้องกัน
การอ่านแฟนตาซี: ธุรกรรมแรกแก้ไขข้อมูลในช่วงที่แน่นอนในแบทช์และธุรกรรมที่สองจะเพิ่มข้อมูลหนึ่งข้อมูลในช่วงนี้ ในเวลานี้การทำธุรกรรมครั้งแรกจะสูญเสียการปรับเปลี่ยนข้อมูลที่เพิ่มขึ้นใหม่
สรุป :
ยิ่งระดับการแยกที่สูงขึ้นเท่าไหร่ก็ยิ่งมั่นใจได้ถึงความสมบูรณ์และความสอดคล้องของข้อมูล แต่ยิ่งส่งผลกระทบต่อประสิทธิภาพการทำงานพร้อมกันมากขึ้นเท่านั้น
ระดับการแยกเริ่มต้นของฐานข้อมูลส่วนใหญ่คือการอ่านที่ได้รับมอบหมายเช่น SQLServer และ Oracle
ระดับการแยกเริ่มต้นของฐานข้อมูลไม่กี่คือ: อ่านซ้ำได้ตัวอย่างเช่น: mysql innodb
iv. ระดับการแยกในฤดูใบไม้ผลิ
V. การทำรังของธุรกรรม
ผ่านความรู้เชิงทฤษฎีข้างต้นเราเข้าใจคุณลักษณะและลักษณะบางอย่างของการทำธุรกรรมฐานข้อมูลและธุรกรรมสปริง ต่อไปเราวิเคราะห์สถานการณ์การทำธุรกรรมที่ซ้อนกันเพื่อทำความเข้าใจกลไกการแพร่กระจายการทำธุรกรรมในฤดูใบไม้ผลิอย่างลึกซึ้ง
สมมติว่าวิธี A () ของบริการธุรกรรมภายนอก A เรียกวิธี B () ของบริการด้านใน B
propagation_required (สปริงเริ่มต้น)
หากระดับธุรกรรมของ ServiceB.Methodb () ถูกกำหนดเป็น propagation_required จากนั้นเมื่อ ServiceA.methoda () ถูกดำเนินการการทำธุรกรรมได้เริ่มขึ้นแล้วในฤดูใบไม้ผลิแล้ว ในเวลานี้ serviceb.methodb () เรียกว่า Serviceb.methodb () เห็นว่ากำลังทำงานอยู่ในการทำธุรกรรมของ Servicea.methoda () และไม่มีการทำธุรกรรมใหม่
หาก serviceb.methodb () กำลังทำงานอยู่มันจะกำหนดธุรกรรมให้กับตัวเอง
ด้วยวิธีนี้หากมีข้อยกเว้นเกิดขึ้นใน servicea.methoda () หรือที่ใดก็ได้ภายใน serviceb.methodb () การทำธุรกรรมจะถูกย้อนกลับ
propagation_requires_new
ตัวอย่างเช่นเราออกแบบว่า servicea.methoda () มีระดับการทำธุรกรรมของ propagation_required และ serviceb.methodb () มีระดับการทำธุรกรรมของ propagation_requires_new
จากนั้นเมื่อมีการดำเนินการ serviceb.methodb () ธุรกรรมที่ servicea.methoda () จะถูกระงับและ serviceb.methodb () จะเริ่มการทำธุรกรรมใหม่และจะดำเนินการต่อไปหลังจากการทำธุรกรรม serviceb.methodb () เสร็จสมบูรณ์
ความแตกต่างระหว่างการทำธุรกรรมและการแพร่กระจายของเขา _Required คือระดับของการย้อนกลับของการทำธุรกรรม เนื่องจาก serviceb.methodb () เป็นธุรกรรมใหม่จึงมีสองธุรกรรมที่แตกต่างกัน หากมีการส่ง serviceb.methodb () แล้ว servicea.methoda () ล้มเหลวในการย้อนกลับ serviceb.methodb () จะไม่ย้อนกลับ หาก serviceb.methodb () ล้มเหลวในการย้อนกลับหากข้อยกเว้นที่ถูกส่งโดย servicea.methoda () ถูกจับการทำธุรกรรม servicea.methoda () อาจยังคงส่ง (ส่วนใหญ่ขึ้นอยู่กับว่าข้อยกเว้นที่ถูกโยนโดย B เป็นข้อยกเว้นที่จะย้อนกลับ)
Propagation_supports
สมมติว่าระดับการทำธุรกรรมของ ServiceB.Methodb () เป็น propagation_supports เมื่อมันถูกดำเนินการไปยัง Serviceb.methodb () หากพบว่า servicea.methoda () ได้เปิดธุรกรรมมันจะเข้าร่วมการทำธุรกรรมปัจจุบัน หากพบว่า servicea.methoda () ไม่ได้เริ่มการทำธุรกรรมมันจะไม่เริ่มการทำธุรกรรม ในเวลานี้การทำธุรกรรมของวิธีการภายในขึ้นอยู่กับการทำธุรกรรมนอกสุด
propagation_nested
สถานการณ์กำลังซับซ้อนมากขึ้นในขณะนี้ คุณสมบัติการทำธุรกรรมของ Serviceb.methodb () ได้รับการกำหนดค่าเป็น propagation_nested ทั้งสองจะร่วมมือกันอย่างไรในเวลานี้? ServiceB#MethodB หากย้อนกลับการทำธุรกรรมภายใน (เช่น ServiceB#MethodB) จะย้อนกลับไปที่ SavePoint ก่อนที่จะดำเนินการในขณะที่การทำธุรกรรมภายนอก (เช่น ServiceA#Methoda) สามารถมีการจัดการสองวิธีต่อไปนี้:
. จับข้อยกเว้นและเรียกใช้ตรรกะสาขายกเว้น
เป็นโมฆะเมธอด () {ลอง {serviceb.methodb (); } catch (someException) {// ดำเนินธุรกิจอื่น ๆ เช่น serviceC.Methodc (); - วิธีนี้ยังเป็นสิ่งที่มีค่าที่สุดเกี่ยวกับการทำธุรกรรมที่ซ้อนกัน มันมีบทบาทในการดำเนินการสาขา หาก ServiceB.Methodb ล้มเหลวดังนั้น ServiceC.Methodc () จะถูกดำเนินการและ ServiceB.Methodb ได้ย้อนกลับไปที่ SavePoint ก่อนที่จะดำเนินการดังนั้นจึงไม่มีการสร้างข้อมูลสกปรก (เทียบเท่ากับวิธีนี้ไม่เคยถูกดำเนินการ) คุณลักษณะนี้สามารถใช้ในบริการพิเศษบางอย่างและไม่ได้ propagation_required หรือ propagation_requires_new สามารถทำสิ่งนี้ได้
ข. รหัสการย้อนกลับ/การทำธุรกรรมภายนอกไม่ได้ทำการแก้ไขใด ๆ หากการทำธุรกรรมภายใน (ServiceB#MethodB) ย้อนกลับ ServiceB.Methodb แรกจะกลับไปที่ SavePoint ก่อนที่จะดำเนินการ (ไม่ว่าในกรณีใด ๆ ) และการทำธุรกรรมภายนอก (เช่น ServiceA#Methoda) จะตัดสินใจว่าจะกระทำหรือย้อนกลับตามการกำหนดค่าที่เฉพาะเจาะจง
แอตทริบิวต์การแพร่กระจายธุรกรรมอีกสามรายการนั้นไม่ได้ผลโดยทั่วไปดังนั้นจึงไม่มีการวิเคราะห์ที่นี่
6. สรุป
สำหรับสถานที่ที่จำเป็นต้องมีการทำธุรกรรมในโครงการฉันขอแนะนำให้นักพัฒนาควรใช้อินเทอร์เฟซ TransactionCallback ของ Spring เพื่อใช้การทำธุรกรรม อย่าใช้คำอธิบายประกอบการทำธุรกรรมสปริงแบบสุ่มสี่สุ่มห้า หากคุณต้องใช้คำอธิบายประกอบคุณต้องมีความเข้าใจอย่างละเอียดเกี่ยวกับกลไกการแพร่กระจายและระดับการแยกการทำธุรกรรมสปริงมิฉะนั้นผลกระทบที่ไม่คาดคิดอาจเกิดขึ้น