บางคนสามารถอธิบายพารามิเตอร์การแยกและการเผยแพร่ที่ใช้สำหรับ@Transactional
คำอธิบายประกอบผ่านตัวอย่างในโลกแห่งความจริงได้หรือไม่
โดยทั่วไปเมื่อใดและทำไมฉันควรเลือกที่จะเปลี่ยนค่าเริ่มต้น
บางคนสามารถอธิบายพารามิเตอร์การแยกและการเผยแพร่ที่ใช้สำหรับ@Transactional
คำอธิบายประกอบผ่านตัวอย่างในโลกแห่งความจริงได้หรือไม่
โดยทั่วไปเมื่อใดและทำไมฉันควรเลือกที่จะเปลี่ยนค่าเริ่มต้น
คำตอบ:
เป็นคำถามที่ดีแม้ว่าจะไม่ใช่คำตอบที่น่ารำคาญก็ตาม
กำหนดวิธีการทำธุรกรรมที่เกี่ยวข้องกับแต่ละอื่น ๆ ตัวเลือกทั่วไป:
Required
: รหัสจะทำงานในธุรกรรมเสมอ สร้างธุรกรรมใหม่หรือนำมาใช้ซ้ำหากมีRequires_new
: รหัสจะทำงานในธุรกรรมใหม่เสมอ ระงับธุรกรรมปัจจุบันหากมีอยู่กำหนดสัญญาข้อมูลระหว่างธุรกรรม
Read Uncommitted
: อนุญาตให้อ่านสกปรกRead Committed
: ไม่อนุญาตให้อ่านสกปรกRepeatable Read
: หากอ่านแถวสองครั้งในธุรกรรมเดียวกันผลลัพธ์จะเหมือนกันเสมอSerializable
: ทำธุรกรรมทั้งหมดตามลำดับระดับที่ต่างกันมีคุณสมบัติด้านประสิทธิภาพที่แตกต่างกันในแอ็พพลิเคชันแบบมัลติเธรด ฉันคิดว่าถ้าคุณเข้าใจdirty reads
แนวคิดคุณจะสามารถเลือกตัวเลือกที่ดี
ตัวอย่างเวลาที่สกปรกสามารถอ่านได้:
thread 1 thread 2
| |
write(x) |
| |
| read(x)
| |
rollback |
v v
value (x) is now dirty (incorrect)
ดังนั้นเริ่มต้นสติ (ถ้าดังกล่าวสามารถอ้าง) อาจจะRead Committed
ซึ่งจะช่วยให้เพียงคุณเท่านั้นที่อ่านค่าที่ได้รับการกระทำโดยการทำธุรกรรมการทำงานอื่น ๆ Required
ในการรวมกันที่มีระดับการขยายพันธุ์ของ จากนั้นคุณสามารถทำงานได้จากที่นั่นหากใบสมัครของคุณมีความต้องการอื่น ๆ
ตัวอย่างที่ใช้งานได้จริงของการทำธุรกรรมใหม่ที่จะถูกสร้างขึ้นเสมอเมื่อเข้าสู่provideService
รูทีนและเสร็จสิ้นเมื่อออกจาก:
public class FooService {
private Repository repo1;
private Repository repo2;
@Transactional(propagation=Propagation.REQUIRES_NEW)
public void provideService() {
repo1.retrieveFoo();
repo2.retrieveFoo();
}
}
หากเราใช้แทนRequired
ธุรกรรมจะยังคงเปิดอยู่หากธุรกรรมนั้นเปิดอยู่แล้วเมื่อเข้าสู่รูทีน โปรดทราบว่าผลลัพธ์ของ a rollback
อาจแตกต่างกันเนื่องจากการประมวลผลหลายรายการสามารถมีส่วนร่วมในธุรกรรมเดียวกัน
เราสามารถตรวจสอบพฤติกรรมได้อย่างง่ายดายด้วยการทดสอบและดูว่าผลลัพธ์แตกต่างกันอย่างไรกับระดับการเผยแพร่:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations="classpath:/fooService.xml")
public class FooServiceTests {
private @Autowired TransactionManager transactionManager;
private @Autowired FooService fooService;
@Test
public void testProvideService() {
TransactionStatus status = transactionManager.getTransaction(new DefaultTransactionDefinition());
fooService.provideService();
transactionManager.rollback(status);
// assert repository values are unchanged ...
}
ด้วยระดับการแพร่กระจายของ
Requires new
เราคาดหวังว่าจะfooService.provideService()
ได้รับการไม่ย้อนกลับเพราะมันสร้างมันขึ้นมาเองย่อยการทำธุรกรรม
Required
: เราคาดหวังว่าทุกอย่างจะถูกย้อนกลับและร้านค้าสำรองไม่เปลี่ยนแปลง
sessionFactory.getCurrentTransaction()
มีการเพิ่มจึงไม่จำเป็นต้องเรียกใช้HibernateTemplate
อีกต่อไปเพื่อจัดการธุรกรรม ฉันลบมันออก :)
PROPAGATION_REQUIRED = 0 ; ถ้า DataSourceTransactionObject T1 ได้เริ่มขึ้นแล้วสำหรับวิธี M1 หากจำเป็นต้องใช้วัตถุธุรกรรม M2 อีกวิธีหนึ่งจะไม่สร้างวัตถุธุรกรรมใหม่ขึ้นมาวัตถุวัตถุ T1 ถูกใช้สำหรับ M2
PROPAGATION_MANDATORY = 2 ; วิธีการจะต้องทำงานภายในการทำธุรกรรม หากไม่มีธุรกรรมที่มีอยู่กำลังดำเนินการข้อยกเว้นจะถูกส่งออกไป
PROPAGATION_REQUIRES_NEW = 3 ; หาก DataSourceTransactionObject T1 ได้เริ่มขึ้นแล้วสำหรับวิธี M1 และอยู่ในระหว่างดำเนินการ (ดำเนินการวิธีการ M1) หากวิธีอื่น M2 เริ่มดำเนินการแล้ว T1 จะถูกระงับในช่วงระยะเวลาของวิธีการ M2 กับ DataSourceTransactionObject T2 สำหรับ M2.M2
PROPAGATION_NOT_SUPPORTED = 4 ; ถ้า DataSourceTransactionObject T1 เริ่มต้นแล้วสำหรับวิธี M1 หากมีวิธีอื่นที่เรียกใช้ M2 พร้อมกันแล้ว M2 ไม่ควรเรียกใช้ภายในบริบทการทำธุรกรรม T1 ถูกระงับจนกว่า M2 จะเสร็จสิ้น
PROPAGATION_NEVER = 5 ; ไม่มีวิธีใดที่ทำงานในบริบทของธุรกรรม
ระดับการแยก: มันเป็นเรื่องเกี่ยวกับจำนวนธุรกรรมที่อาจได้รับผลกระทบจากกิจกรรมของการทำธุรกรรมพร้อมกันอื่น ๆ มันเป็นความสอดคล้องสนับสนุนการออกจากข้อมูลในหลายตารางในสถานะที่สอดคล้องกัน มันเกี่ยวข้องกับการล็อคแถวและ / หรือตารางในฐานข้อมูล
มีปัญหากับการทำธุรกรรมหลายรายการ
สถานการณ์ที่ 1หากธุรกรรม T1 อ่านข้อมูลจากตาราง A1 ที่เขียนโดยธุรกรรม T2 พร้อมกันอื่นหากวิธีที่ T2 เป็นการย้อนกลับข้อมูลที่ได้รับจาก T1 นั้นไม่ถูกต้องหนึ่งข้อมูล e = a 2 เป็นข้อมูลดั้งเดิมถ้า T1 อ่าน a = 1 ที่เขียนโดย T2 ถ้าย้อนกลับ T2 แล้ว = 1 จะย้อนกลับไปเป็น = 2 ใน DB.But ตอนนี้ T1 มี = 1 แต่ในตาราง DB จะเปลี่ยนเป็น = 2
สถานการณ์ที่ 2. ถ้าธุรกรรม T1 อ่านข้อมูลจากตาราง A1 หากข้อมูลการอัพเดทธุรกรรม (T2) พร้อมกันอีกรายการในตาราง A1 จากนั้นข้อมูลที่ T1 ได้อ่านนั้นแตกต่างจากตาราง A1 เนื่องจาก T2 ได้อัปเดตข้อมูลในตาราง A1 แล้วถ้า T1 อ่าน a = 1 และ T2 อัปเดต a = 2. จากนั้น a! = b
สถานการณ์ที่ 3หากธุรกรรม T1 อ่านข้อมูลจากตาราง A1 ด้วยจำนวนแถวที่แน่นอน ถ้าธุรกรรมอื่นพร้อมกัน (T2) แทรกแถวเพิ่มเติมในตาราง A1 จำนวนแถวที่อ่านโดย T1 จะแตกต่างจากแถวบนตาราง A1
สถานการณ์ที่ 1 เรียกว่าDirty reads
สถานการณ์ที่ 2 เรียกว่าการอ่านที่ไม่สามารถทำซ้ำได้
สถานการณ์ 3 เรียกว่าPhantom อ่าน
ดังนั้นระดับการแยกคือส่วนขยายที่สถานการณ์ 1, สถานการณ์ 2, สถานการณ์ 3สามารถป้องกันได้ คุณสามารถรับระดับการแยกโดยสมบูรณ์ได้โดยใช้การล็อกซึ่งเป็นการป้องกันการอ่านและเขียนข้อมูลเดียวกันในเวลาเดียวกัน แต่มันส่งผลกระทบต่อประสิทธิภาพการทำงานระดับการแยกขึ้นอยู่กับแอปพลิเคชันไปยังแอปพลิเคชัน
ISOLATION_READ_UNCOMMITTED : อนุญาตให้อ่านการเปลี่ยนแปลงที่ยังไม่ได้รับการยอมรับมันประสบกับสถานการณ์ที่ 1, สถานการณ์ที่ 2, สถานการณ์ที่ 3
ISOLATION_READ_COMMITTED : อนุญาตให้อ่านจากธุรกรรมที่เกิดขึ้นพร้อมกัน อาจประสบจากสถานการณ์ที่ 2 และสถานการณ์ที่ 3 เนื่องจากธุรกรรมอื่น ๆ อาจมีการอัพเดทข้อมูล
ISOLATION_REPEATABLE_READ : การอ่านหลาย ๆ ครั้งของเขตข้อมูลเดียวกันจะให้ผลลัพธ์เดียวกันจนกว่าจะมีการเปลี่ยนแปลงด้วยตัวเองมันอาจประสบจากสถานการณ์ที่ 3 เพราะการทำธุรกรรมอื่น ๆ อาจจะแทรกข้อมูล
ISOLATION_SERIALIZABLE : สถานการณ์ที่ 1, สถานการณ์ที่ 2, สถานการณ์ที่ 3 ไม่เคยเกิดขึ้นมันคือการแยกที่สมบูรณ์มันเกี่ยวข้องกับการล็อคเต็มมัน affets performace เพราะการล็อค
คุณสามารถทดสอบการใช้
public class TransactionBehaviour {
// set is either using xml Or annotation
DataSourceTransactionManager manager=new DataSourceTransactionManager();
SimpleTransactionStatus status=new SimpleTransactionStatus();
;
public void beginTransaction()
{
DefaultTransactionDefinition Def = new DefaultTransactionDefinition();
// overwrite default PROPAGATION_REQUIRED and ISOLATION_DEFAULT
// set is either using xml Or annotation
manager.setPropagationBehavior(XX);
manager.setIsolationLevelName(XX);
status = manager.getTransaction(Def);
}
public void commitTransaction()
{
if(status.isCompleted()){
manager.commit(status);
}
}
public void rollbackTransaction()
{
if(!status.isCompleted()){
manager.rollback(status);
}
}
Main method{
beginTransaction()
M1();
If error(){
rollbackTransaction()
}
commitTransaction();
}
}
คุณสามารถตรวจแก้จุดบกพร่องและดูผลลัพธ์ที่มีค่าแตกต่างกันสำหรับการแยกและการเผยแพร่
คำอธิบายอื่น ๆ ที่เพียงพอเกี่ยวกับแต่ละพารามิเตอร์จะได้รับจากคำตอบอื่น ๆ ; อย่างไรก็ตามคุณขอตัวอย่างโลกแห่งความจริงนี่คือตัวอย่างที่อธิบายวัตถุประสงค์ของตัวเลือกการแพร่กระจายที่แตกต่างกัน:
สมมติว่าคุณรับผิดชอบในการใช้บริการสมัครสมาชิกซึ่งอีเมลยืนยันถูกส่งไปยังผู้ใช้ คุณมีเซอร์วิสออบเจ็กต์สองชิ้นอันหนึ่งสำหรับการลงทะเบียนผู้ใช้และอีกอันสำหรับการส่งอีเมลซึ่งอันหลังถูกเรียกใช้ในอันแรก ตัวอย่างเช่นสิ่งนี้:/* Sign Up service */
@Service
@Transactional(Propagation=REQUIRED)
class SignUpService{
...
void SignUp(User user){
...
emailService.sendMail(User);
}
}
/* E-Mail Service */
@Service
@Transactional(Propagation=REQUIRES_NEW)
class EmailService{
...
void sendMail(User user){
try{
... // Trying to send the e-mail
}catch( Exception)
}
}
คุณอาจสังเกตเห็นว่าบริการที่สองเป็นประเภทการเผยแพร่REQUIRES_NEWและมีโอกาสมากกว่าที่จะเกิดข้อผิดพลาด (เซิร์ฟเวอร์ SMTP ไม่ถูกต้องอีเมลที่ไม่ถูกต้องหรือเหตุผลอื่น ๆ ) คุณอาจไม่ต้องการให้กระบวนการทั้งหมดย้อนกลับเช่น ลบข้อมูลผู้ใช้ออกจากฐานข้อมูลหรือสิ่งอื่น ๆ ดังนั้นคุณจึงเรียกบริการที่สองในการทำธุรกรรมแยกต่างหาก
กลับไปที่ตัวอย่างของเราในครั้งนี้คุณมีความกังวลเกี่ยวกับความปลอดภัยของฐานข้อมูลดังนั้นคุณจึงกำหนดคลาส DAO ของคุณด้วยวิธีนี้:/* User DAO */
@Transactional(Propagation=MANDATORY)
class UserDAO{
// some CRUD methods
}
หมายความว่าเมื่อใดก็ตามที่มีการสร้างออบเจ็กต์ DAO และด้วยเหตุนี้จึงมีการสร้างฐานข้อมูลที่มีศักยภาพเราจำเป็นต้องสร้างความมั่นใจว่าการโทรนั้นเกิดจากภายในบริการของเราซึ่งหมายความว่าธุรกรรมสดควรมีอยู่ มิฉะนั้นข้อยกเว้น occurs.Therefore การขยายพันธุ์เป็นประเภทบังคับ
ระดับการแยกกำหนดวิธีที่การเปลี่ยนแปลงที่เกิดขึ้นกับที่เก็บข้อมูลบางรายการโดยธุรกรรมหนึ่งส่งผลกระทบต่อธุรกรรมที่เกิดขึ้นพร้อมกันอื่น ๆ และวิธีการและเวลาที่ข้อมูลที่เปลี่ยนแปลงนั้นพร้อมใช้งานกับธุรกรรมอื่น เมื่อเรากำหนดธุรกรรมโดยใช้ Spring Framework เราสามารถกำหนดระดับการแยกที่ธุรกรรมเดียวกันจะถูกดำเนินการ
@Transactional(isolation=Isolation.READ_COMMITTED)
public void someTransactionalMethod(Object obj) {
}
READ_UNCOMMITTED ระดับการแยกระบุว่าธุรกรรมอาจอ่านข้อมูลที่ยังคงปราศจากข้อผูกมัดโดยธุรกรรมอื่น ๆ
READ_COMMITTED ระดับการแยกระบุว่าการทำธุรกรรมไม่สามารถอ่านข้อมูลที่ยังไม่ได้กระทำโดยการทำธุรกรรมอื่น ๆ
REPEATABLE_READ ระดับการแยกระบุว่าถ้าธุรกรรมอ่านหนึ่งเร็กคอร์ดจากฐานข้อมูลหลายครั้งผลลัพธ์ของการดำเนินการอ่านเหล่านั้นทั้งหมดต้องเหมือนกันเสมอ
ระดับการแยกแบบ SERIALIZABLE เป็นระดับการแยกที่ จำกัด มากที่สุด การทำธุรกรรมจะดำเนินการด้วยการล็อคในทุกระดับ (อ่านช่วงและเขียนล็อค) ดังนั้นพวกเขาจะปรากฏราวกับว่าพวกเขาถูกดำเนินการในลักษณะที่ต่อเนื่องกัน
การเผยแผ่คือความสามารถในการตัดสินใจว่าวิธีการทางธุรกิจควรจะห่อหุ้มในการทำธุรกรรมทั้งทางตรรกะหรือทางกายภาพ
ลักษณะการทำงานของ Spring REQUIRED หมายถึงว่าจะใช้ธุรกรรมเดียวกันหากมีธุรกรรมที่เปิดอยู่แล้วในบริบทการดำเนินการเมธอด bean ปัจจุบัน
REQUIRES_NEW พฤติกรรมหมายความว่าการทำธุรกรรมทางกายภาพใหม่จะถูกสร้างขึ้นโดยภาชนะ
พฤติกรรม NESTED ทำให้ธุรกรรม Spring ที่ซ้อนกันใช้ฟิสิคัลธุรกรรมเดียวกัน แต่ตั้งค่าจุดบันทึกระหว่างการเรียกใช้ที่ซ้อนกันดังนั้นธุรกรรมภายในอาจย้อนกลับแยกต่างหากจากธุรกรรมภายนอก
พฤติกรรมของ MANDATORY ระบุว่าธุรกรรมที่เปิดอยู่ต้องมีอยู่แล้ว หากไม่มีข้อยกเว้นจะถูกโยนโดยภาชนะ
พฤติกรรมที่ไม่เคยระบุว่าการทำธุรกรรมที่เปิดอยู่จะต้องไม่มีอยู่ หากการทำธุรกรรมมีข้อยกเว้นจะถูกโยนโดยภาชนะ
พฤติกรรม NOT_SUPPORTED จะดำเนินการนอกขอบเขตของการทำธุรกรรมใด ๆ หากการทำธุรกรรมที่เปิดอยู่มีอยู่แล้วมันจะถูกหยุดชั่วคราว
พฤติกรรมของ SUPPORTS จะดำเนินการในขอบเขตของการทำธุรกรรมหากมีการทำธุรกรรมที่เปิดอยู่แล้ว หากไม่มีธุรกรรมที่เปิดอยู่วิธีจะดำเนินการต่อไป แต่ใช้วิธีที่ไม่ทำธุรกรรม
ธุรกรรมหมายถึงหน่วยงานที่ใช้กับฐานข้อมูล
ในTransactionDefinition
ส่วนต่อประสานฤดูใบไม้ผลิที่กำหนดคุณสมบัติของธุรกรรมที่เข้ากันได้กับ Spring @Transactional
คำอธิบายประกอบอธิบายคุณสมบัติการทำธุรกรรมในวิธีการหรือชั้นเรียน
@Autowired
private TestDAO testDAO;
@Transactional(propagation=TransactionDefinition.PROPAGATION_REQUIRED,isolation=TransactionDefinition.ISOLATION_READ_UNCOMMITTED)
public void someTransactionalMethod(User user) {
// Interact with testDAO
}
การขยายพันธุ์ (Reproduction):ใช้สำหรับความสัมพันธ์ระหว่างธุรกรรม (คล้ายกับการสื่อสารระหว่างเธรด Java)
+-------+---------------------------+------------------------------------------------------------------------------------------------------+
| value | Propagation | Description |
+-------+---------------------------+------------------------------------------------------------------------------------------------------+
| -1 | TIMEOUT_DEFAULT | Use the default timeout of the underlying transaction system, or none if timeouts are not supported. |
| 0 | PROPAGATION_REQUIRED | Support a current transaction; create a new one if none exists. |
| 1 | PROPAGATION_SUPPORTS | Support a current transaction; execute non-transactionally if none exists. |
| 2 | PROPAGATION_MANDATORY | Support a current transaction; throw an exception if no current transaction exists. |
| 3 | PROPAGATION_REQUIRES_NEW | Create a new transaction, suspending the current transaction if one exists. |
| 4 | PROPAGATION_NOT_SUPPORTED | Do not support a current transaction; rather always execute non-transactionally. |
| 5 | PROPAGATION_NEVER | Do not support a current transaction; throw an exception if a current transaction exists. |
| 6 | PROPAGATION_NESTED | Execute within a nested transaction if a current transaction exists. |
+-------+---------------------------+------------------------------------------------------------------------------------------------------+
การแยก:การแยกเป็นหนึ่งในคุณสมบัติของกรด (Atomicity, Consistency, Isolation, Durability) ของธุรกรรมฐานข้อมูล การแยกกำหนดว่าผู้ใช้และระบบอื่นมองเห็นความสมบูรณ์ของการทำธุรกรรมได้อย่างไร มันใช้สำหรับการล็อคทรัพยากรคือการควบคุมการเกิดพร้อมกันตรวจสอบให้แน่ใจว่ามีเพียงหนึ่งธุรกรรมเท่านั้นที่สามารถเข้าถึงทรัพยากร ณ จุดที่กำหนด
การรับรู้ล็อค:ระดับการแยกกำหนดระยะเวลาที่จะมีการล็อค
+---------------------------+-------------------+-------------+-------------+------------------------+
| Isolation Level Mode | Read | Insert | Update | Lock Scope |
+---------------------------+-------------------+-------------+-------------+------------------------+
| READ_UNCOMMITTED | uncommitted data | Allowed | Allowed | No Lock |
| READ_COMMITTED (Default) | committed data | Allowed | Allowed | Lock on Committed data |
| REPEATABLE_READ | committed data | Allowed | Not Allowed | Lock on block of table |
| SERIALIZABLE | committed data | Not Allowed | Not Allowed | Lock on full table |
+---------------------------+-------------------+-------------+-------------+------------------------+
อ่านการรับรู้:ปัญหาที่สำคัญ 3 ประเภทต่อไปนี้เกิดขึ้น:
UPDATES
จาก tx อื่นINSERTS
และ / หรือDELETES
จาก tx อื่นระดับการแยกด้วยการอ่านประเภทต่างๆ:
+---------------------------+----------------+----------------------+----------------+
| Isolation Level Mode | Dirty reads | Non-repeatable reads | Phantoms reads |
+---------------------------+----------------+----------------------+----------------+
| READ_UNCOMMITTED | allows | allows | allows |
| READ_COMMITTED (Default) | prevents | allows | allows |
| REPEATABLE_READ | prevents | prevents | allows |
| SERIALIZABLE | prevents | prevents | prevents |
+---------------------------+----------------+----------------------+----------------+
คุณแทบไม่เคยต้องการที่จะใช้Read Uncommited
เพราะมันไม่ได้เป็นACID
ไปตามจริงๆ Read Commmited
เป็นจุดเริ่มต้นที่ดี Repeatable Read
อาจจำเป็นต้องใช้ในการรายงานการยกเลิกหรือการรวมสถานการณ์เท่านั้น โปรดทราบว่าฐานข้อมูลจำนวนมากรวม postgres ไม่สนับสนุนการอ่านซ้ำคุณต้องใช้Serializable
แทน Serializable
มีประโยชน์สำหรับสิ่งที่คุณรู้ว่าจะต้องเกิดขึ้นอย่างสมบูรณ์เป็นอิสระจากสิ่งอื่นใด; คิดเหมือนsynchronized
ใน Java serializable ไปจับมือกับREQUIRES_NEW
การแพร่กระจาย
ฉันใช้REQUIRES
สำหรับฟังก์ชั่นทั้งหมดที่เรียกใช้แบบสอบถาม UPDATE หรือ DELETE รวมถึงฟังก์ชั่นระดับ "บริการ" สำหรับฟังก์ชั่นระดับ DAO ที่รันเฉพาะ SELECTs ฉันจะใช้SUPPORTS
ซึ่งจะเข้าร่วมใน TX หากมีการเริ่มต้นแล้ว (เช่นถูกเรียกจากฟังก์ชั่นบริการ)
การแยกธุรกรรมและการขยายการทำธุรกรรมแม้ว่าจะเกี่ยวข้องกัน แต่มีแนวคิดที่แตกต่างกันสองอย่างชัดเจน ในทั้งสองกรณีมีการปรับแต่งค่าเริ่มต้นที่ส่วนลูกค้าเขตแดนโดยใช้การจัดการรายการบอกเล่าหรือจัดการการทำธุรกรรมการเขียนโปรแกรม รายละเอียดของแต่ละระดับการแยกและแอตทริบิวต์การเผยแพร่สามารถพบได้ในลิงค์อ้างอิงด้านล่าง
สำหรับการทำธุรกรรม / การเชื่อมต่อกับฐานข้อมูลที่กำหนดอย่างน้อยสองรายการการเปลี่ยนแปลงที่ทำโดยเคียวรีในธุรกรรมหนึ่งจะมีผลกระทบ / สามารถมองเห็นได้จากเคียวรีในธุรกรรมอื่น นอกจากนี้ยังเกี่ยวข้องกับชนิดของการล็อกระเบียนฐานข้อมูลที่จะใช้เพื่อแยกการเปลี่ยนแปลงในธุรกรรมนี้จากธุรกรรมอื่นและในทางกลับกัน โดยทั่วไปจะใช้งานโดยฐานข้อมูล / ทรัพยากรที่เข้าร่วมในการทำธุรกรรม
.
ในแอปพลิเคชันองค์กรสำหรับคำขอ / การประมวลผลที่กำหนดมีองค์ประกอบหลายอย่างที่เกี่ยวข้องเพื่อให้งานเสร็จสมบูรณ์ ส่วนประกอบบางส่วนทำเครื่องหมายขอบเขต (เริ่มต้น / สิ้นสุด) ของธุรกรรมที่จะใช้ในองค์ประกอบที่เกี่ยวข้องและเป็นส่วนประกอบย่อย สำหรับขอบเขตของธุรกรรมนี้การเผยแพร่รายการระบุว่าองค์ประกอบนั้นจะเกี่ยวข้องหรือไม่เข้าร่วมในการทำธุรกรรมและจะเกิดอะไรขึ้นถ้าองค์ประกอบการโทรมีอยู่แล้วหรือไม่มีธุรกรรมที่สร้าง / เริ่มต้นแล้ว นี่เป็นเช่นเดียวกับคุณสมบัติธุรกรรม Java EE โดยทั่วไปแล้วสิ่งนี้จะถูกใช้งานโดยตัวจัดการทรานแซคชัน / ผู้จัดการการเชื่อมต่อ
อ้างอิง:
ฉันได้ทำงานouterMethod
, method_1
และmethod_2
ด้วยโหมดการขยายพันธุ์ที่แตกต่างกัน
ด้านล่างเป็นผลลัพธ์สำหรับโหมดการขยายพันธุ์ที่แตกต่างกัน
วิธีการด้านนอก
@Transactional
@Override
public void outerMethod() {
customerProfileDAO.method_1();
iWorkflowDetailDao.method_2();
}
Method_1
@Transactional(propagation=Propagation.MANDATORY)
public void method_1() {
Session session = null;
try {
session = getSession();
Temp entity = new Temp(0l, "XXX");
session.save(entity);
System.out.println("Method - 1 Id "+entity.getId());
} finally {
if (session != null && session.isOpen()) {
}
}
}
Method_2
@Transactional()
@Override
public void method_2() {
Session session = null;
try {
session = getSession();
Temp entity = new Temp(0l, "CCC");
session.save(entity);
int i = 1/0;
System.out.println("Method - 2 Id "+entity.getId());
} finally {
if (session != null && session.isOpen()) {
}
}
}
เราสามารถเพิ่มสำหรับสิ่งนี้:
@Transactional(readOnly = true)
public class Banking_CustomerService implements CustomerService {
public Customer getDetail(String customername) {
// do something
}
// these settings have precedence for this method
@Transactional(readOnly = false, propagation = Propagation.REQUIRES_NEW)
public void updateCustomer(Customer customer) {
// do something
}
}
คุณสามารถใช้สิ่งนี้:
@Transactional(propagation = Propagation.REQUIRES_NEW)
public EventMessage<ModificaOperativitaRapporto> activate(EventMessage<ModificaOperativitaRapporto> eventMessage) {
//here some transaction related code
}
คุณสามารถใช้สิ่งนี้ได้เช่นกัน:
public interface TransactionStatus extends SavepointManager {
boolean isNewTransaction();
boolean hasSavepoint();
void setRollbackOnly();
boolean isRollbackOnly();
void flush();
boolean isCompleted();
}