วิธีการ @Transactional เรียกวิธีอื่นโดยไม่ต้องมี @Transactional anotation?


89

ผมเคยเห็นวิธีการในระดับบริการที่ถูกระบุว่าเป็น@Transactionalแต่มันก็ยังเรียกร้องวิธีการอื่น ๆ @Transactionalบางอย่างในระดับเดียวกันกับที่ซึ่งไม่ได้ทำเครื่องหมายว่าเป็น

หมายความว่าการเรียกใช้เมธอดแยกกันทำให้แอปพลิเคชันเปิดการเชื่อมต่อแยกกับ DB หรือระงับการทำธุรกรรมหลักเป็นต้น?

ลักษณะการทำงานเริ่มต้นสำหรับวิธีการที่ไม่มีคำอธิบายประกอบใด ๆ ซึ่งเรียกโดยวิธีอื่นที่มี@Transactionalคำอธิบายประกอบ?

คำตอบ:


119

เมื่อคุณเรียกใช้เมธอดโดยไม่@Transactionalอยู่ในบล็อกธุรกรรมธุรกรรมหลักจะไปยังเมธอดใหม่ จะใช้การเชื่อมต่อเดียวกันจากเมธอดหลัก (ด้วย@Transactional) และข้อยกเว้นใด ๆ ที่เกิดขึ้นในเมธอดที่เรียกว่า (โดยไม่@Transactionalทำให้ธุรกรรมย้อนกลับตามที่กำหนดค่าไว้ในข้อกำหนดธุรกรรม

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

คุณสามารถค้นหารายละเอียดเพิ่มเติมในส่วนการ declarative จัดการการทำธุรกรรมของเอกสารการทำธุรกรรมในฤดูใบไม้ผลิ

แบบจำลองการทำธุรกรรมที่เปิดเผยในฤดูใบไม้ผลิใช้พร็อกซี AOP ดังนั้นพร็อกซี AOP จึงเป็นผู้รับผิดชอบในการสร้างธุรกรรม พร็อกซี AOP จะใช้งานได้ก็ต่อเมื่อมีการเรียกเมธอดในอินสแตนซ์จากด้านนอกของอินสแตนซ์


นั่นคือพฤติกรรมเริ่มต้นของฤดูใบไม้ผลิหรือไม่?
goe

ใช่. มันเป็นพฤติกรรมเริ่มต้น
Arun P Johny

2
@Tomasz ครับ แต่ควรกล่าวถึงด้วยว่าการเปลี่ยนการเผยแพร่ธุรกรรมบนเมธอดที่เรียกจากเมธอด @Transactional อื่นจะไม่มีผล
ฟิล

1
@Tomasz will follow the transaction definitions given in the called methodนั่นคือสิ่งที่ผมหมายโดยกล่าวว่า แต่ถ้าการโทรมาจากอินสแตนซ์อ็อบเจ็กต์เดียวกันจะไม่มีผลใด ๆ เนื่องจากการโทรจะไม่แพร่กระจายผ่านพร็อกซี aop ซึ่งรับผิดชอบการดูแลธุรกรรม
Arun P Johny

5
@Filip ไม่ถูกต้องทั้งหมดหากคุณเรียกเมธอดที่มี@Transactionalนิยามจากอ็อบเจ็กต์ / อินสแตนซ์ที่แตกต่างกันแม้ว่าเมธอดการเรียกจะมี@Transactionalแอ็ตทริบิวต์ที่แตกต่างกันแต่เมธอดที่เรียกนั้นจะเป็นไปตามนิยามธุรกรรมของมันเอง
Arun P Johny

24
  • นั่นหมายความว่าการเรียกใช้เมธอดแยกต่างหากทำให้แอปพลิเคชันเปิดการเชื่อมต่อแยกกับ DB หรือระงับการทำธุรกรรมหลัก ฯลฯ หรือไม่?

นั่นขึ้นอยู่กับระดับการขยายพันธุ์ นี่คือค่าระดับที่เป็นไปได้ทั้งหมดทั้งหมด

ตัวอย่างเช่นในกรณีที่ระดับการเผยแพร่เป็นNESTEDธุรกรรมปัจจุบันจะ "ระงับ" และธุรกรรมใหม่จะถูกสร้างขึ้น ( หมายเหตุ: การสร้างธุรกรรมที่ซ้อนกันจริงจะใช้ได้เฉพาะกับผู้จัดการธุรกรรมเฉพาะเท่านั้น )

  • ลักษณะการทำงานเริ่มต้นสำหรับวิธีการที่ไม่มีคำอธิบายประกอบใด ๆ ที่เรียกโดยวิธีการอื่นด้วยคำอธิบายประกอบ @Transactional คืออะไร

ระดับการขยายพันธุ์ต้น (สิ่งที่คุณเรียกว่า "พฤติกรรม") เป็นที่จำเป็น ในกรณีที่มีการเรียกเมธอด "ภายใน" ที่มี@Transactionalคำอธิบายประกอบอยู่ (หรือทำธุรกรรมโดยประกาศผ่าน XML) จะดำเนินการภายในธุรกรรมเดียวกันเช่น "ไม่มีอะไรใหม่" ถูกสร้างขึ้น


แล้วการโทรย่อยของ NOT_SUPPORTED ที่ไม่มีคำอธิบายประกอบล่ะ มันสืบทอด NOT_Supported หรือพวกเขาเปิดธุรกรรมใหม่โดยที่ REQURED เป็นค่าเริ่มต้น? ตัวอย่างเช่น: f1.call () {f2 ()} ที่มีคำอธิบายประกอบ NOT_SUPPORTED สำหรับ f1 และไม่ใช่สำหรับ f2
Dave

8

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

หากมีการเรียกวิธีอื่นที่มีคำอธิบายประกอบ @Transactional การเผยแพร่จะขึ้นอยู่กับแอตทริบิวต์การแพร่กระจายของคำอธิบายประกอบนั้น


คำตอบทั้ง 3 ข้อขัดแย้งกันในระดับหนึ่งไม่แน่ใจว่าข้อใดถูกต้องกว่ากัน
Trump 2020 - ความยุติธรรมจะมาถึง

1
@EricWang แค่อยากจะแบ่งปันว่าฉันได้ทดสอบสถานการณ์นี้ในวันนี้และคำตอบโดยArun P Johny (พร้อมความคิดเห็น)นั้นถูกต้องที่สุดสำหรับสถานการณ์การเรียกร้องภายในนี้
Vinay Vissh

3

เมธอดด้านในจะส่งผลต่อเมธอดภายนอกหากเมธอดด้านในไม่ได้ใส่คำอธิบายประกอบด้วย @Transactional

ในกรณีที่วิธีการด้านในมีคำอธิบายประกอบ @Transactional ด้วยสิ่งREQUIRES_NEWต่อไปนี้จะเกิดขึ้น

...
@Autowired
private TestDAO testDAO;

@Autowired
private SomeBean someBean;

@Override
@Transactional(propagation=Propagation.REQUIRED)
public void outerMethod(User user) {
  testDAO.insertUser(user);
  try{
    someBean.innerMethod();
  } catch(RuntimeException e){
    // handle exception
  }
}


@Override
@Transactional(propagation=Propagation.REQUIRES_NEW)
public void innerMethod() {
  throw new RuntimeException("Rollback this transaction!");
}

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


1
เพื่อความชัดเจนสำหรับผู้เริ่มต้นฉันค่อนข้างแน่ใจว่า innerMethod () ต้องอยู่บน bean อื่น (aka Spring-managed java Object) มากกว่า outerMethod () หากทั้งคู่อยู่ในถั่วเดียวกันฉันไม่คิดว่า innerMethod จะใช้พฤติกรรมการทำธุรกรรมที่ประกาศไว้ในคำอธิบายประกอบ แต่จะใช้สิ่งที่ประกาศไว้ในการประกาศ outerMethod () นี่เป็นเพราะวิธีที่ Spring จัดการกับ AOP ซึ่งใช้สำหรับคำอธิบายประกอบ@Transactional ( docs.spring.io/spring/docs/3.0.x/spring-framework-reference/… )
จอห์นซิเมอร์
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.