2012-01-18 27 views
8

ठीक है, मुझे प्रतिबद्धता और रोलबैक के बीच का अंतर पता है और इन परिचालनों को क्या करना है। हालांकि, मुझे यकीन नहीं है कि मामलों में क्या करना है जहां मैं प्रतिबद्ध(), रोलबैक() और/या कुछ भी नहीं करते समय एक ही व्यवहार प्राप्त कर सकता हूं।जावा: प्रतिबद्ध बनाम रोलबैक बनाम कुछ भी नहीं जब semantics अपरिवर्तित है?

उदाहरण के लिए, मान लीजिए कि मेरे पास निम्न कोड है जो डीबी: पर लिखने के बिना एक क्वेरी निष्पादित करता है, मैं एक ऐसे अनुप्रयोग पर काम कर रहा हूं जो SQLite डेटाबेस के साथ संचार करता है।

try { 
    if (deleteById(2)) 
    // a) delete successful (1 row deleted) 
    else 
    // b) delete unsuccessful (0 row deleted, no errors) 
} catch (SQLException e) { 
    // c) delete failed (because of an error (possibly due to constraint violation in DB)) 
} 

गौर करें कि एक अर्थ के दृष्टिकोण से, प्रतिबद्ध या मामलों में रोलबैक कर ख) और ग) में परिणाम:

try { 
    doSomeQuery() 
    // b) success 
} catch (SQLException e) { 
    // a) failed (because of exception) 
} 

या और भी दिलचस्प है, तो निम्न कोड है, जो एक ही पंक्ति को हटा देता है पर विचार वही व्यवहार

आम तौर पर, प्रत्येक मामले के अंदर करने के लिए कई विकल्प हैं (क, ख, ग):

  • प्रतिबद्ध
  • रोलबैक

कुछ नहीं कर क्या कोई मार्गनिर्देश हैं या एक विशेष ऑपरेशन चुनने के प्रदर्शन लाभ? सही तरीका क्या है?

नोट: मान लें कि ऑटो-प्रतिबद्ध अक्षम है।

+1

तो यह संभव है प्रतिबद्ध करने के लिए तेजी से हो जाएगा। रोलबैक के लिए डीबी को लेनदेन लॉग की जांच करने और किए गए किसी भी बदलाव को वापस करने की आवश्यकता है। भले ही यह "कोई परिवर्तन नहीं" हो, फिर भी चेक दिखाई देगा। – JNK

+0

रोलबैक एक ही लेनदेन में किए गए अन्य अपडेटों को पूर्ववत कर देगा। जहां आपके पास केवल एक है, इससे कोई फर्क नहीं पड़ता है (जेएनके के वर्णन के अलावा) लेकिन यदि आप बाद में एक और जोड़ते हैं और इसे संभालना भूल जाते हैं तो आप काट सकते हैं। अंदर आने के लिए एक अच्छी आदत। –

+1

@ जेएनके जो आरडीबीएम पर थोड़ा निर्भर है - ट्रिगर्स के इंस्टीटैड के साथ भी संभावित संघर्ष है - लेकिन यह कुछ हद तक शांत हो जाएगा। – Andrew

उत्तर

2

यदि यह सिर्फ एक चयन है, तो मैं एक लेनदेन नहीं खोलूंगा और इसलिए, किसी भी मामले में कुछ भी करने के लिए कुछ भी नहीं है। शायद आप पहले से ही जानते हैं कि एक अद्यतन/सम्मिलन है क्योंकि आप पहले से ही पैरामीटर पारित कर चुके हैं। वह मामला जहां आप एक हेरफेर करना चाहते हैं, अधिक दिलचस्प है। जिस मामले में इसे हटाया जाता है वह स्पष्ट है कि आप प्रतिबद्ध होना चाहते हैं; यदि कोई अपवाद है तो कुछ विफल होने के बाद डीबी को लगातार रखने के लिए आपको रोलबैक करना चाहिए और ऐसा कुछ नहीं है जो आप कर सकते हैं। अगर हटाना विफल रहा क्योंकि वहाँ से हटाने के लिए मैं 3 कारणों के लिए प्रतिबद्ध था कुछ भी नहीं था:

  • शब्दार्थ रूप में इसे और अधिक सही के बाद से संचालन किया गया तकनीकी रूप से सफल और निर्दिष्ट के रूप में प्रदर्शन लगता है।

  • यह अधिक भविष्य सबूत इसलिए यदि किसी को लेन-देन के लिए और अधिक कोड कहते हैं कि वे इसे वापस क्योंकि एक चल रहा है हटाने बस कुछ भी नहीं किया साथ आश्चर्य नहीं होगा (वे अपवाद उस पर उम्मीद करेंगे लेनदेन वापस लुढ़का गया है)

  • जब कोई ऑपरेशन होता है, तो प्रतिबद्धता तेज होती है लेकिन इस मामले में मैं यह महत्वपूर्ण नहीं मानता।

+0

+1, लेकिन: (1) "यदि यह सिर्फ एक चयन है, तो मैं एक लेनदेन नहीं खोलूंगा" डीबीएमएस पर निर्भर करता है, क्योंकि कुछ में, आप * हमेशा * एक ट्रान्सएक्शन में होते हैं; और (2) मैं आपसे सहमत हूं कि आपको अपवाद के साथ मामला वापस लेना चाहिए, लेकिन यह "कोई चर्चा नहीं है" कहने के लिए एक पुलिस-आउट है, क्योंकि ओपी ने विशेष रूप से इस मामले के बारे में पूछा था, एक रोल-बैक और एक प्रतिबद्धता अर्थात् समकक्ष होगी। – ruakh

+0

@ruakh (1) मैं पूरी तरह से सहमत हूं। के लिए (2) मैंने टिप्पणी – Luis

+0

पर लेने के लिए जवाब संपादित किया है जेडीबीसी हमेशा एक लेनदेन शुरू करता है (जो या तो ऑटोोकॉमिट है, या मैन्युअल रूप से प्रतिबद्ध/रोलडबैक होना आवश्यक है)। लेनदेन शुरू करने के लिए कोई विकल्प नहीं है। कुछ डेटाबेस में 'रीडोनली' कनेक्शन विकल्प होता है जिसका अर्थ है कि उस कनेक्शन के लिए सस्ता लेनदेन हैंडलिंग। –

1

किसी भी गैर-तुच्छ अनुप्रयोग में संचालन के लिए कई SQL कथनों की आवश्यकता होती है। पहले SQL कथन के बाद और अंतिम SQL कथन से पहले कोई विफलता डेटा को असंगत होने का कारण बनती है।

लेन-देन एकाधिक-कथन संचालन को परमाणु के रूप में डिज़ाइन करने के लिए डिज़ाइन किए गए हैं जो एकल-कथन संचालन के रूप में वर्तमान में काम कर रहे हैं।

1

क्या आप कह रहे हैं कोड बुलाया जा रहा है पर निर्भर करता है, यह एक झंडा आप के खिलाफ परीक्षण करने के लिए है, या यह विशेष रूप से अपवाद फेंक कुछ गलत हो जाता है, तो करता है के लिए वापस आ रहा है?

एपीआई अपवाद फेंकता है, लेकिन यह भी एक बूलियन रिटर्न (सच | गलत):

यह स्थिति एक बहुत होता है, और यह, यह मुश्किल बुला कोड दोनों स्थितियों को संभालने के लिए के लिए बनाता है के रूप में आप में बताया अपने ओपी। एक बात आप इस स्थिति में क्या कर सकते हैं:

कोई समस्या नहीं है:

// Initialize a var we can test against later 
// Lol, didn't realize this was for java, please excuse the var 
// initialization, as it's demonstrative only 
$queryStatus = false; 

try { 
    if (deleteById(2)) { 
     $queryStatus = true; 
    } else { 
     // I can do a few things here 
     // Skip it, because the $queryStatus was initialized as false, so 
     // nothing changes 
     // Or throw an exception to be caught 
     throw new SQLException('Delete failed'); 
    }   
} catch (SQLException $e) { 
    // This can also be skipped, because the $queryStatus was initialized as 
    // false, however you may want to do some logging 
    error_log($e->getMessage());  
} 

// Because we have a converged variable which covers both cases where the API 
// may return a bool, or throw an exception we can test the value and determine 
// whether rollback or commit 
if (true === $queryStatus) { 
    commit(); 
} else { 
    rollback(); 
} 

एपीआई विशेष रूप से अपवाद (कोई वापसी मान) फेंकता है। हम मान सकते हैं कि अगर कोई अपवाद नहीं पकड़ा गया, तो ऑपरेशन बिना त्रुटि के पूरा हो गया और हम कोशिश/पकड़ ब्लॉक के भीतर रोलबैक()/प्रतिबद्ध() जोड़ सकते हैं।

यह

if (deleteById(2)) { 
    commit(); 
} else { 
    rollback(); 
} 

जाँच अगर आपके पास/पुराने स्कूल त्रुटि हैंडलिंग के लिए वापस चला जाता है: | (झूठे सच)

try { 
    deleteById(2); 

    // Because the API dev had a good grasp of error handling by using 
    // exceptions, we can also do some other calls 
    updateById(7); 

    insertByName('Chargers rule'); 

    // No exception thrown from above API calls? sweet, lets commit 
    commit(); 

} catch (SQLException $e) { 

    // Oops exception was thrown from API, lets roll back 
    rollback(); 
} 

एपीआई किसी भी अपवाद केवल एक bool रिटर्न फेंक नहीं है, कई लेन-देन को बनाने प्रश्नों, आप # 1 परिदृश्य से ही वर विचार उधार ले सकते हैं:

$queryStatus = true; 

if (!deleteById(2)) { 
    $queryStatus = false; 
} 

if (!updateById(7)) { 
    $queryStatus = false; 
} 

... 

if (true === $queryStatus) { 
    commit(); 
} else { 
    rollback(); 
} 

"नोट: मान लें कि ऑटो-प्रतिबद्ध अक्षम है।"

  • एक बार जब आप को अक्षम स्वतः-लिखें, आप आरडीबीएमएस है कि आप से प्रतिबद्ध के नियंत्रण ले जा रहे हैं कह रहे हैं अब तक ऑटो प्रतिबद्ध फिर से सक्षम है, इसलिए IMO, यह अच्छा अभ्यास या तो रोलबैक करने के लिए या बनाम लेनदेन के लिए प्रतिबद्ध लिम्बो में कोई प्रश्न छोड़ना।
1

मैं अपने आप को ठीक उसी प्रश्न पूछा। अंत में मैं एक समाधान के लिए गया जहां मैंने हमेशा सफल लेनदेन किया और हमेशा गैर-सफल लेन-देन का कोई प्रभाव नहीं पड़ा। यह कोड के सरलीकृत बहुत सारे और इसे स्पष्ट और पढ़ने के लिए और अधिक आसान बना दिया।

यह आवेदन मैंने काम किया है, जिसमें .net पर NHibernate + SQLite इस्तेमाल किया में किसी भी बड़े प्रदर्शन की समस्याओं नहीं था। आपका मिलेज भिन्न हो सकता है।

1

उनके जवाब में कहा गया है दूसरों के रूप में, यह है, जो मेरा मानना ​​है कि न के बराबर है (समकक्ष मामलों आप वर्णित के लिए) प्रदर्शन की बात नहीं है, लेकिन रख-रखाव की बात है, और यह कभी बहुत महत्वपूर्ण है! के लिए अपने कोड (कोई बात नहीं क्या) अच्छी तरह से पोषणीय, मेरा सुझाव है होना करने के लिए हमेशा अपने try ब्लॉक के बिल्कुल नीचे प्रतिबद्ध करने के लिए और हमेशा अपने finally ब्लॉक में अपने Connection बंद करने के लिए

आदेश में। finally ब्लॉक में यदि आपको असामान्य लेनदेन हैं (जिसका अर्थ है कि आप try ब्लॉक के अंत में प्रतिबद्धता तक नहीं पहुंच पाए हैं तो ब्लॉक भी आपको रोलबैक करना चाहिए)।

यह उदाहरण दिखाता है क्या मेरा मानना ​​है कि सबसे अच्छा अभ्यास (miantainability वार) है: डेटाबेस एक खुला लेन-देन हुआ

public boolean example() 
{ 
    Connection conn; 
    ... 
    try 
    { 
     ... 
     //Do your SQL magic (that can throw exceptions) 
     ... 
     conn.commit(); 
     return true; 
    } 
    catch(...) 
    { 
     ... 
     return false; 
    } 
    finally 
    {//Close statements, connections, etc 
     ... 
     closeConn(conn); 
    } 
} 

public static void closeConn(Connection conn) 
{ 
    if (conn != null) 
     if (!conn.isClosed()) 
     { 
      if (!conn.getAutoCommit()) 
       conn.rollback();//If we need to close() but there are uncommitted transacitons (meaning there have been problems) 
      conn.close(); 
      conn = null; 
     } 
} 
+0

अच्छा। हालांकि मैं झूठी वापसी के बजाए, रास्ते में त्रुटि संदेश जैसे किसी भी उपयोगी त्रुटि जानकारी को खोने के माध्यम से बबल को अपवाद भी नहीं दूंगा। – vidstige

संबंधित मुद्दे