Spring @Transactional - การแยกการเผยแพร่


447

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

โดยทั่วไปเมื่อใดและทำไมฉันควรเลือกที่จะเปลี่ยนค่าเริ่มต้น

คำตอบ:


442

เป็นคำถามที่ดีแม้ว่าจะไม่ใช่คำตอบที่น่ารำคาญก็ตาม

การเผยแผ่

กำหนดวิธีการทำธุรกรรมที่เกี่ยวข้องกับแต่ละอื่น ๆ ตัวเลือกทั่วไป:

  • 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: เราคาดหวังว่าทุกอย่างจะถูกย้อนกลับและร้านค้าสำรองไม่เปลี่ยนแปลง


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

@ Donal โอ้ขอโทษที่ยังไม่ชัดเจน ประเด็นของฉันคือเนื่องจากsessionFactory.getCurrentTransaction()มีการเพิ่มจึงไม่จำเป็นต้องเรียกใช้HibernateTemplateอีกต่อไปเพื่อจัดการธุรกรรม ฉันลบมันออก :)
Johan Sjöberg

คำถามของฉันเป็นเพียงเกี่ยวกับลิงก์ชี้ไปที่จริง :-)
Donal Fellows

วิธีรับการเปลี่ยนแปลงที่เกิดขึ้นในท
Prasanna Kumar HA

304

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();
    }

}

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


วิธีรับการเปลี่ยนแปลงที่เกิดขึ้นในท
Prasanna Kumar HA

2
การทำงานร่วมกันระหว่างระดับการแยกและการเผยแพร่คืออะไร? หากวิธีที่ 1 เริ่มต้นธุรกรรมที่มีระดับการแยกพูดว่า READ_COMMITTED และหลังจากนั้นเรียกใช้ method2 ที่มีระดับ REPEATABLE_READ แน่นอนว่าวิธีที่ 2 จะต้องดำเนินการด้วยตนเองในธุรกรรมใหม่โดยไม่คำนึงถึงพฤติกรรมการเผยแพร่ที่ระบุ (เช่น REQUIRED เท่านั้น)
Cornel Masson

นี่มันสายไปแล้วสำหรับการแสดง แต่เมื่อ PROPAGATION_REQUIRES_NEW เกิดอะไรขึ้นกับ T1 (ซึ่งใช้โดย M1) หากมีการโทรใหม่อีกครั้งเกิดขึ้นกับ M1 (พูด M1.1)
ทิม Z

115

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

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

/* 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 การขยายพันธุ์เป็นประเภทบังคับ


26
ตัวอย่างที่สมบูรณ์แบบสำหรับ REQUIRES_NEW
Ravi Thapliyal

5
คำอธิบายที่ดี! โดยค่าเริ่มต้นสำหรับการเผยแพร่คืออะไร? นอกจากนี้ยังจะดียิ่งขึ้นถ้าคุณสามารถยกตัวอย่างเช่นนี้สำหรับการแยกเช่นกัน ขอบคุณมาก.
Prakash K

5
@PrakashK Default จำเป็นต้องมี ( docs.spring.io/spring-framework/docs/current/javadoc-api/org/… )
ihebiheb

59

ระดับการแยกกำหนดวิธีที่การเปลี่ยนแปลงที่เกิดขึ้นกับที่เก็บข้อมูลบางรายการโดยธุรกรรมหนึ่งส่งผลกระทบต่อธุรกรรมที่เกิดขึ้นพร้อมกันอื่น ๆ และวิธีการและเวลาที่ข้อมูลที่เปลี่ยนแปลงนั้นพร้อมใช้งานกับธุรกรรมอื่น เมื่อเรากำหนดธุรกรรมโดยใช้ 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 จะดำเนินการในขอบเขตของการทำธุรกรรมหากมีการทำธุรกรรมที่เปิดอยู่แล้ว หากไม่มีธุรกรรมที่เปิดอยู่วิธีจะดำเนินการต่อไป แต่ใช้วิธีที่ไม่ทำธุรกรรม


4
หากคุณสามารถเพิ่มเวลาที่จะใช้อันใดจะเป็นประโยชน์มากขึ้น
Kumar Manish

ยกตัวอย่างบางอย่างมันจะมีประโยชน์มากสำหรับผู้เริ่มต้น
nitinsridar

23

ธุรกรรมหมายถึงหน่วยงานที่ใช้กับฐานข้อมูล

ใน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 ประเภทต่อไปนี้เกิดขึ้น:

  • Dirty reads : อ่านข้อมูลที่ไม่ได้รับการยอมรับจาก tx อื่น (ธุรกรรม)
  • ไม่สามารถอ่านซ้ำได้ : อ่านUPDATESจาก tx อื่น
  • Phantom reads : อ่านที่ได้ทำ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       |
+---------------------------+----------------+----------------------+----------------+

ตัวอย่าง


20

คุณแทบไม่เคยต้องการที่จะใช้Read Uncommitedเพราะมันไม่ได้เป็นACIDไปตามจริงๆ Read Commmitedเป็นจุดเริ่มต้นที่ดี Repeatable Readอาจจำเป็นต้องใช้ในการรายงานการยกเลิกหรือการรวมสถานการณ์เท่านั้น โปรดทราบว่าฐานข้อมูลจำนวนมากรวม postgres ไม่สนับสนุนการอ่านซ้ำคุณต้องใช้Serializableแทน Serializableมีประโยชน์สำหรับสิ่งที่คุณรู้ว่าจะต้องเกิดขึ้นอย่างสมบูรณ์เป็นอิสระจากสิ่งอื่นใด; คิดเหมือนsynchronizedใน Java serializable ไปจับมือกับREQUIRES_NEWการแพร่กระจาย

ฉันใช้REQUIRESสำหรับฟังก์ชั่นทั้งหมดที่เรียกใช้แบบสอบถาม UPDATE หรือ DELETE รวมถึงฟังก์ชั่นระดับ "บริการ" สำหรับฟังก์ชั่นระดับ DAO ที่รันเฉพาะ SELECTs ฉันจะใช้SUPPORTSซึ่งจะเข้าร่วมใน TX หากมีการเริ่มต้นแล้ว (เช่นถูกเรียกจากฟังก์ชั่นบริการ)


13

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

การแยกธุรกรรม

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

.

การขยายการทำธุรกรรม

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

อ้างอิง:


1
เยี่ยมมากข้อมูลทั้งหมดในที่เดียวลิงก์มีประโยชน์มากขอบคุณ @Gladwin Burboz
nitinsridar

7

ฉันได้ทำงาน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()) {
            }
        }
    }
      • outerMethod - โดยไม่ต้องทำธุรกรรม
      • method_1 - การแพร่กระจายผู้บังคับบัญชา) -
      • method_2 - คำอธิบายประกอบธุรกรรมเท่านั้น
      • ผลลัพธ์: method_1 จะมีข้อยกเว้นว่าไม่มีธุรกรรมที่มีอยู่
      • outerMethod - โดยไม่ต้องทำธุรกรรม
      • method_1 - คำอธิบายประกอบธุรกรรมเท่านั้น
      • method_2 - การขยายพันธุ์คำสั่ง)
      • ผลลัพธ์: method_2 จะส่งข้อยกเว้นว่าไม่มีธุรกรรมที่มีอยู่
      • ผลลัพธ์: method_1 จะคงอยู่ในฐานข้อมูล
      • outerMethod - ด้วยธุรกรรม
      • method_1 - คำอธิบายประกอบธุรกรรมเท่านั้น
      • method_2 - การขยายพันธุ์คำสั่ง)
      • ผลลัพธ์: method_2 จะเก็บบันทึกไว้ในฐานข้อมูล
      • ผลลัพธ์: method_1 จะคงอยู่ในฐานข้อมูล - ที่นี่ธุรกรรมหลักภายนอกที่มีอยู่ใช้สำหรับทั้งวิธีที่ 1 และ 2
      • outerMethod - ด้วยธุรกรรม
      • method_1 - การแพร่กระจายผู้บังคับบัญชา) -
      • method_2 - คำอธิบายประกอบธุรกรรมเท่านั้นและส่งข้อยกเว้น
      • เอาท์พุท: ไม่มีบันทึกอยู่ในฐานข้อมูลหมายถึงการย้อนกลับเสร็จแล้ว
      • outerMethod - ด้วยธุรกรรม
      • method_1 - การขยายพันธุ์ REQUIRES_NEW)
      • method_2 - Propagation.REQUIRES_NEW) และส่งข้อยกเว้น 1/0
      • เอาต์พุต: method_2 จะส่งข้อยกเว้นดังนั้นเมธอด _2 จะไม่คงอยู่
      • ผลลัพธ์: method_1 จะคงอยู่ในฐานข้อมูล
      • ผลลัพธ์: ไม่มีวิธีย้อนกลับสำหรับ method_1

3

เราสามารถเพิ่มสำหรับสิ่งนี้:

@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
    }
}

1

คุณสามารถใช้สิ่งนี้:

@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();
}
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.