ธุรกรรมกับ Spring และ JPA

1. ภาพรวม

บทช่วยสอนนี้จะกล่าวถึงวิธีที่ถูกต้องในการกำหนดค่าธุรกรรมในช่วงฤดูใบไม้ผลิวิธีใช้คำอธิบายประกอบ@Transactionalและข้อผิดพลาดทั่วไป

สำหรับการสนทนาเชิงลึกเพิ่มเติมเกี่ยวกับการกำหนดค่าการคงอยู่หลักโปรดดูบทช่วยสอน Spring with JPA

โดยทั่วไปมีสองวิธีที่แตกต่างกันในการกำหนดค่าธุรกรรม - คำอธิบายประกอบและ AOP แต่ละวิธีมีข้อดีของตัวเอง เราจะพูดถึงการกำหนดค่าคำอธิบายประกอบทั่วไปที่นี่

2. กำหนดค่าธุรกรรม

ฤดูใบไม้ผลิ 3.1 แนะนำ@EnableTransactionManagementบันทึกย่อที่เราสามารถใช้ใน@Configurationระดับและเปิดใช้งานการสนับสนุนการทำธุรกรรม:

@Configuration @EnableTransactionManagement public class PersistenceJPAConfig{ @Bean public LocalContainerEntityManagerFactoryBean entityManagerFactoryBean(){ //... } @Bean public PlatformTransactionManager transactionManager(){ JpaTransactionManager transactionManager = new JpaTransactionManager(); transactionManager.setEntityManagerFactory( entityManagerFactoryBean().getObject() ); return transactionManager; } }

แต่ถ้าเรากำลังใช้โครงการ Boot ฤดูใบไม้ผลิและมีฤดูใบไม้ผลิ DATA- * หรือฤดูใบไม้ผลิ-TX อ้างอิงใน classpath แล้วจัดการการทำธุรกรรมจะเปิดใช้งานโดยค่าเริ่มต้น

3. กำหนดค่าธุรกรรมด้วย XML

ก่อน 3.1 หรือถ้า Java ไม่ใช่อ็อพชันนี่คือคอนฟิกูเรชัน XML โดยใช้คำอธิบายประกอบเป็นตัวขับเคลื่อนและการสนับสนุนเนมสเปซ:

4. คำอธิบายประกอบ@Transactional

ด้วยการกำหนดค่าธุรกรรมตอนนี้เราสามารถใส่คำอธิบายประกอบ bean ด้วย@Transactional ได้ทั้งในระดับคลาสหรือวิธีการ:

@Service @Transactional public class FooService { //... }

คำอธิบายประกอบรองรับการกำหนดค่าเพิ่มเติมเช่นกัน:

  • การขยายพันธุ์ประเภทของการทำธุรกรรม
  • ระดับการแยกของการทำธุรกรรม
  • หมดเวลาสำหรับการดำเนินงานห่อโดยการทำธุรกรรม
  • ธงอ่านได้อย่างเดียว - คำแนะนำสำหรับผู้ให้บริการการติดตาว่าการทำธุรกรรมที่ควรจะอ่านอย่างเดียว
  • ย้อนกลับกฎสำหรับการทำธุรกรรม

โปรดทราบว่าโดยค่าเริ่มต้นการย้อนกลับจะเกิดขึ้นสำหรับรันไทม์ยกเว้นที่ไม่ได้เลือกเท่านั้น ข้อยกเว้นที่ตรวจสอบไม่ได้ทำให้เกิดการย้อนกลับของธุรกรรม แน่นอนเราสามารถกำหนดค่าลักษณะการทำงานนี้ด้วยพารามิเตอร์rollbackForและnoRollbackFor annotation

5. ข้อผิดพลาดที่อาจเกิดขึ้น

5.1. ธุรกรรมและผู้รับมอบฉันทะ

ในระดับสูงSpring จะสร้างพร็อกซีสำหรับคลาสทั้งหมดที่ใส่คำอธิบายประกอบด้วย@Transactional - ไม่ว่าจะในคลาสหรือวิธีใดก็ได้ พร็อกซีอนุญาตให้เฟรมเวิร์กฉีดลอจิกทรานแซคชันก่อนและหลังวิธีการทำงาน - ส่วนใหญ่สำหรับการเริ่มต้นและการทำธุรกรรม

สิ่งสำคัญที่ต้องจำไว้คือหาก Transactional bean กำลังใช้งานอินเทอร์เฟซโดยค่าเริ่มต้นพร็อกซีจะเป็น Java Dynamic Proxy ซึ่งหมายความว่าเฉพาะการเรียกเมธอดภายนอกที่เข้ามาผ่านพร็อกซีเท่านั้นที่จะถูกดักฟัง การเรียกด้วยตนเองจะไม่เริ่มต้นธุรกรรมใด ๆแม้ว่าเมธอดนั้นจะมีคำอธิบายประกอบ@Transactionalก็ตาม

ข้อแม้อีกประการหนึ่งของการใช้พร็อกซีคือเฉพาะเมธอดสาธารณะเท่านั้นที่ควรใส่คำอธิบายประกอบด้วย@Transactional วิธีการมองเห็นอื่น ๆ จะเพิกเฉยต่อคำอธิบายประกอบอย่างเงียบ ๆ เนื่องจากไม่ได้รับมอบฉันทะ

บทความนี้กล่าวถึงข้อผิดพลาดในการพร็อกซีเพิ่มเติมโดยละเอียดที่นี่

5.2. การเปลี่ยนระดับการแยก

นอกจากนี้เรายังสามารถเปลี่ยนระดับการแยกธุรกรรม:

@Transactional(isolation = Isolation.SERIALIZABLE)

โปรดทราบว่าสิ่งนี้ถูกนำมาใช้จริงใน Spring 4.1; หากเราเรียกใช้ตัวอย่างข้างต้นก่อนฤดูใบไม้ผลิ 4.1 จะส่งผลให้:

org.springframework.transaction.InvalidIsolationLevelException : มาตรฐาน JPA ไม่รองรับระดับการแยกที่กำหนดเอง - ใช้JpaDialectพิเศษสำหรับการใช้งาน JPA ของคุณ

5.3. ธุรกรรมอ่านอย่างเดียว

อ่านได้อย่างเดียวธงมักจะสร้างความสับสนโดยเฉพาะอย่างยิ่งเมื่อทำงานกับ JPA; จาก Javadoc:

นี่เป็นเพียงคำใบ้สำหรับระบบย่อยธุรกรรมจริง มันจะไม่จำเป็นต้องทำให้เกิดความล้มเหลวของความพยายามในการเข้าถึงการเขียน ตัวจัดการธุรกรรมที่ไม่สามารถตีความคำใบ้แบบอ่านอย่างเดียวจะไม่เกิดข้อยกเว้นเมื่อถูกถามถึงธุรกรรมแบบอ่านอย่างเดียว

ความจริงก็คือเราไม่สามารถมั่นใจได้ว่าการแทรกหรือการอัปเดตจะไม่เกิดขึ้นเมื่อตั้งค่าสถานะreadOnly พฤติกรรมนี้ขึ้นอยู่กับผู้ขายในขณะที่ JPA เป็นผู้ขายที่ไม่เชื่อเรื่องพระเจ้า

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

@Transactional( propagation = Propagation.SUPPORTS,readOnly = true )

จากบริบทที่ไม่ใช่ธุรกรรม - ธุรกรรมจะไม่ถูกสร้างขึ้นและแฟล็ก readOnlyจะถูกละเว้น

5.4. การบันทึกธุรกรรม

วิธีที่เป็นประโยชน์ในการทำความเข้าใจปัญหาที่เกี่ยวข้องกับธุรกรรมคือการปรับแต่งการบันทึกในแพ็คเกจธุรกรรม แพ็กเกจที่เกี่ยวข้องใน Spring คือ " org.springframework.transaction" ซึ่งควรกำหนดค่าด้วยระดับการบันทึกของ TRACE

6. บทสรุป

เราได้กล่าวถึงการกำหนดค่าพื้นฐานของความหมายของธุรกรรมโดยใช้ทั้ง Java และ XML วิธีใช้@Transactionalและแนวทางปฏิบัติที่ดีที่สุดของกลยุทธ์การทำธุรกรรม

เช่นเคยรหัสที่นำเสนอในบทความนี้มีอยู่ใน Github