SQLAlchemy: फ्लश () और कमिट () के बीच क्या अंतर है?


422

SQLAlchemy में flush()और क्या अंतर है commit()?

मैंने डॉक्स पढ़ा है, लेकिन कोई भी समझदार नहीं है - वे एक पूर्व-धारणा को समझते हैं जो मेरे पास नहीं है।

मैं विशेष रूप से स्मृति उपयोग पर उनके प्रभाव में रुचि रखता हूं। मैं फ़ाइलों की एक श्रृंखला से डेटाबेस में कुछ डेटा लोड कर रहा हूं (कुल मिलाकर लगभग 5 मिलियन पंक्तियाँ) और मेरा सत्र कभी-कभार गिर रहा है - यह एक बड़ा डेटाबेस और एक मशीन है जिसमें बहुत अधिक मेमोरी नहीं है।

मैं सोच रहा था कि क्या मैं बहुत अधिक commit()और पर्याप्त flush()कॉल का उपयोग कर रहा हूं - लेकिन वास्तव में यह समझने के बिना कि अंतर क्या है, यह बताना मुश्किल है!

जवाबों:


533

एक सेशन ऑब्जेक्ट मूल रूप से डेटाबेस में बदलाव (अपडेट, इंसर्ट, डिलीट) का चलन है। ये ऑपरेशन तब तक डेटाबेस के लिए बने नहीं रहते हैं जब तक वे प्रतिबद्ध नहीं होते हैं (यदि आपका कार्यक्रम मध्य-सत्र के लेन-देन में किसी कारण से रद्द हो जाता है, तो भीतर कोई भी परिवर्तन नहीं हुआ है)।

सत्र ऑब्जेक्ट के साथ लेन-देन संचालन को पंजीकृत session.add()करता है, लेकिन अभी तक उन्हें डेटाबेस तक संचार नहीं करता है जब तक session.flush()कि बुलाया नहीं जाता है।

session.flush()डेटाबेस के लिए संचालन की एक श्रृंखला को सम्मिलित करता है (सम्मिलित करें, अपडेट करें, हटाएं)। डेटाबेस उन्हें एक लेनदेन में लंबित संचालन के रूप में रखता है। जब तक डेटाबेस मौजूदा लेनदेन के लिए COMMIT प्राप्त नहीं करता (जो होता session.commit()है) तब तक परिवर्तन स्थायी रूप से डिस्क पर या अन्य लेनदेन के लिए दिखाई नहीं देता है ।

session.commit() उन परिवर्तनों को डेटाबेस में रखता है (जारी रखता है)।

flush()है हमेशा के लिए एक कॉल के हिस्से के रूप में बुलाया commit()( 1 )।

जब आप डेटाबेस को क्वेरी करने के लिए एक सेशन ऑब्जेक्ट का उपयोग करते हैं, तो क्वेरी डेटाबेस से और अनवांटेड ट्रांजेक्शन के फ्लश किए गए हिस्सों से दोनों परिणाम देगा। डिफ़ॉल्ट रूप से, सत्र autoflushउनके संचालन को ऑब्जेक्ट करता है, लेकिन इसे अक्षम किया जा सकता है।

उम्मीद है कि इस उदाहरण से यह स्पष्ट हो जाएगा:

#---
s = Session()

s.add(Foo('A')) # The Foo('A') object has been added to the session.
                # It has not been committed to the database yet,
                #   but is returned as part of a query.
print 1, s.query(Foo).all()
s.commit()

#---
s2 = Session()
s2.autoflush = False

s2.add(Foo('B'))
print 2, s2.query(Foo).all() # The Foo('B') object is *not* returned
                             #   as part of this query because it hasn't
                             #   been flushed yet.
s2.flush()                   # Now, Foo('B') is in the same state as
                             #   Foo('A') was above.
print 3, s2.query(Foo).all() 
s2.rollback()                # Foo('B') has not been committed, and rolling
                             #   back the session's transaction removes it
                             #   from the session.
print 4, s2.query(Foo).all()

#---
Output:
1 [<Foo('A')>]
2 [<Foo('A')>]
3 [<Foo('A')>, <Foo('B')>]
4 [<Foo('A')>]

बस एक और बात: क्या आप जानते हैं कि कॉलिंग कमिट () उपयोग की गई मेमोरी को बढ़ाता है, या घटाता है?
AP257

2
यह db इंजनों के लिए भी गलत है जो myisam जैसे लेनदेन का समर्थन नहीं करते हैं। जैसा कि कोई चल रहा लेन-देन नहीं है, फ्लश में भी कम से कम खुद को अलग करने के लिए है।
underrun

1
@underrun तो अगर मैं session.query() बाद में करूं session.flush(), तो क्या मुझे अपने बदलाव दिखाई देंगे? यह देखते हुए कि मैं MyISAM का उपयोग कर रहा हूं।
फ्रोजन फ्लेम

1
यह उपयोग करने के लिए अच्छा है या गरीब शैली है flush()और commit(), या मैं कीमिया है कि ऊपर छोड़ देना चाहिए। मैंने flush()कुछ मामलों में उपयोग किया क्योंकि बाद के प्रश्नों को नया डेटा लेने की आवश्यकता थी।
जेन्स

1
@ उपयोग autoflush( Trueडिफ़ॉल्ट रूप से)। यह स्वचालित रूप से सभी प्रश्नों से पहले फ्लश करेगा, इसलिए आपको हर बार याद करने की आवश्यकता नहीं है।
किरण जोनलगड्डा

24

जैसा @ सनापशो कहता है

flush() डेटाबेस के लिए अपने एसक्यूएल बयान भेजता है

commit() लेन-देन करता है।

कब session.autocommit == False:

commit()flush()यदि आप सेट करते हैं तो कॉल करेगा autoflush == True

कब session.autocommit == True:

commit()यदि आपने लेन-देन शुरू नहीं किया है, तो आप कॉल नहीं कर सकते हैं (जो कि आपने शायद नहीं किया है क्योंकि आप मैन्युअल रूप से लेनदेन को प्रबंधित करने से बचने के लिए केवल इस मोड का उपयोग करेंगे)।

इस मोड में, आपको flush()अपने ORM परिवर्तनों को सहेजने के लिए कॉल करना होगा । प्रभावी रूप से फ्लश आपके डेटा को भी प्रभावित करता है।


24
"अगर आपका ऑटोफ़्लश == ट्रू है तो कमिट () फ्लश () कहेगा।" पूरी तरह से सही नहीं है, या सिर्फ भ्रामक है। आटोफ़्लश सेटिंग की परवाह किए बिना हमेशा फ्लश करें।
इल्जा एवरिल

3
autoflushपरम नियंत्रित होता है कि SQLAlchemy पहले एक फ्लश जारी करेगा अगर वहाँ एक प्रश्न जारी करने और प्रतिबद्ध पर अपरिहार्य फ्लश को नियंत्रित करने के साथ कोई संबंध नहीं है के समक्ष लंबित लेखन कर रहे हैं।
सुपरशॉट

4

अगर आप कमिट कर सकते हैं तो फ्लश क्यों करें?

डेटाबेस और sqlalchemy के साथ काम करने के लिए किसी नए के रूप में, पिछले जवाब - कि flush()एसबी को एसक्यूएल बयान भेजता है और commit()उन्हें जारी रखता है - मेरे लिए स्पष्ट नहीं थे। परिभाषाएं समझ में आती हैं, लेकिन यह परिभाषाओं से तुरंत स्पष्ट नहीं है कि आप सिर्फ कमिट करने के बजाय फ्लश का उपयोग क्यों करेंगे।

चूंकि एक कमिट हमेशा फ्लश करता है ( https://docs.sqlalchemy.org/en/13/orm/session_basics.html#committing ) ये ध्वनि वास्तव में समान हैं। मुझे लगता है कि उजागर करने के लिए बड़ा मुद्दा यह है कि एक फ्लश स्थायी नहीं है और इसे पूर्ववत किया जा सकता है, जबकि एक प्रतिबद्ध स्थायी है, इस अर्थ में कि आप डेटाबेस को अंतिम प्रतिबद्ध को पूर्ववत् करने के लिए नहीं कह सकते हैं (मुझे लगता है)

@snapshoe इस बात पर प्रकाश डालता है कि यदि आप डेटाबेस को क्वेरी करना चाहते हैं और ऐसे परिणाम प्राप्त करना चाहते हैं जिसमें नई जोड़े गए ऑब्जेक्ट शामिल हैं, तो आपको पहले फ्लश करना होगा (या प्रतिबद्ध, जो आपके लिए फ्लश होगा)। शायद यह कुछ लोगों के लिए उपयोगी है, हालांकि मुझे यकीन नहीं है कि आप प्रतिबद्ध होने के बजाय फ्लश क्यों करना चाहते हैं (तुच्छ उत्तर के अलावा यह पूर्ववत किया जा सकता है)।

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

इस पर मेरी पोस्ट देखें: क्या sqlalchemy में कमिट करने के लिए ऐड बनाम डिलीट का कोई ऑर्डर है

इसी तरह, किसी ने जानना चाहा कि क्या कमिट करते समय एड ऑर्डर को बनाए रखा जाता है, यानी अगर मैं ऐड करता हूं , object1तो डेटाबेस में जोड़ा जाता है इससे पहले क्या SQLAlchemy ऑर्डर को सत्र में जोड़ने पर ऑर्डर सेव करता है?object2object1object2

फिर, यहाँ संभवतः फ्लश () का उपयोग वांछित व्यवहार को सुनिश्चित करेगा। इसलिए सारांश में, फ्लश के लिए एक उपयोग ऑर्डर गारंटी (मुझे लगता है) प्रदान करने के लिए है, फिर भी अपने आप को "पूर्ववत" विकल्प देने की अनुमति देता है जो प्रतिबद्ध नहीं करता है।

ऑटोफ्लश और ऑटोकॉमिट

ध्यान दें, किसी अद्यतन डेटाबेस पर क्वेरीज़ को सुनिश्चित करने के लिए ऑटोफ़्लश का उपयोग किया जा सकता है क्योंकि क्वेरी निष्पादित करने से पहले sqlalchemy फ्लश होगा। https://docs.sqlalchemy.org/en/13/orm/session_api.html#sqlalchemy.orm.session.Session.params.autoflush

ऑटोकॉमिट कुछ और है जो मुझे पूरी तरह से समझ में नहीं आता है लेकिन ऐसा लगता है कि इसका उपयोग हतोत्साहित करता है: https://docs.sqlalchemy.org/en/13/orm/session_api.html#sqlalchemy.orm.session.Spar.params। autocommit

स्मृति उपयोग

अब मूल प्रश्न वास्तव में स्मृति उद्देश्यों के लिए फ्लश बनाम प्रतिबद्ध के प्रभाव के बारे में जानना चाहता था। जैसा कि जारी रखने या न करने की क्षमता कुछ है जो डेटाबेस प्रदान करता है (मुझे लगता है), बस निस्तब्धता डेटाबेस को लोड करने के लिए पर्याप्त होना चाहिए - हालांकि कमिटिंग को चोट नहीं पहुंचनी चाहिए (वास्तव में शायद मदद करता है - नीचे देखें) यदि आप पूर्ववत करने की परवाह नहीं करते हैं ।

sqlalchemy उन वस्तुओं के लिए कमजोर संदर्भों का उपयोग करता है जिन्हें फ्लश किया गया है: https://docs.sqlalchemy.org/en/13/orm/session_state_management.html#session-referencing-bevivior

इसका मतलब यह है कि यदि आपके पास स्पष्ट रूप से कहीं पर कोई वस्तु नहीं है, जैसे सूची या तानाशाही में, sqlalchemy इसे स्मृति में नहीं रखेगा।

हालाँकि, फिर आपके पास चिंता करने के लिए चीजों का डेटाबेस पक्ष है। संभवत: बिना कमिट किए फ्लशिंग लेनदेन को बनाए रखने के लिए कुछ मेमोरी पेनल्टी के साथ आता है। फिर से, मैं इसके लिए नया हूं लेकिन यहां एक लिंक दिया गया है जो ठीक यही सुझाव देता है: https://stackoverflow.com/a/15305650/730365

दूसरे शब्दों में, कमिट्स को मेमोरी के उपयोग को कम करना चाहिए, हालांकि संभवतः स्मृति और प्रदर्शन के बीच एक व्यापार बंद है। दूसरे शब्दों में, आप शायद हर एक डेटाबेस परिवर्तन, एक समय में (प्रदर्शन कारणों के लिए) नहीं करना चाहते हैं, लेकिन बहुत लंबे समय तक प्रतीक्षा करने से मेमोरी का उपयोग बढ़ेगा।


1

यह मूल प्रश्न का कड़ाई से जवाब नहीं देता है लेकिन कुछ लोगों ने उल्लेख किया है कि आपके साथ session.autoflush = Trueइसका उपयोग नहीं करना है session.flush()... और यह हमेशा सच नहीं होता है।

यदि आप लेन-देन के बीच में एक नई बनाई गई वस्तु की आईडी का उपयोग करना चाहते हैं , तो आपको कॉल करना होगा session.flush()

# Given a model with at least this id
class AModel(Base):
   id = Column(Integer, primary_key=True)  # autoincrement by default on integer primary key

session.autoflush = True

a = AModel()
session.add(a)
a.id  # None
session.flush()
a.id  # autoincremented integer

इसका कारण यह है autoflushकरता नहीं ऑटो आईडी भरने (हालांकि वस्तु का एक प्रश्न है जो कभी कभी "क्यों इस यहाँ लेकिन वहाँ नहीं काम करता है?" के रूप में भ्रम की स्थिति पैदा कर सकते हैं, लेकिन snapshoe पहले से ही इस हिस्से कवर)।


एक संबंधित पहलू जो मेरे लिए बहुत महत्वपूर्ण लगता है और वास्तव में उल्लेख नहीं किया गया था:

आप हर समय क्यों नहीं करेंगे? - जवाब है परमाणुता

कहने के लिए एक फैंसी शब्द: संचालन की एक टुकड़ी को सभी को सफलतापूर्वक निष्पादित करना होगा या उनमें से कोई भी प्रभावी नहीं होगा।

उदाहरण के लिए, यदि आप किसी ऑब्जेक्ट (ए) को बनाना / अपडेट / डिलीट करना चाहते हैं और फिर किसी अन्य (बी) को बनाने / अपडेट / डिलीट करना चाहते हैं, लेकिन यदि (बी) विफल रहता है तो आप (ए) को वापस करना चाहते हैं। इसका मतलब है कि वे 2 ऑपरेशन परमाणु हैं

इसलिए, यदि (बी) को (ए) के परिणाम की आवश्यकता है, तो आप flush(ए) और commitबाद (बी) को कॉल करना चाहते हैं ।

इसके अलावा, अगर session.autoflush is True, उस मामले को छोड़कर, जिसका मैंने ऊपर या दूसरों के जिम्बो उत्तर में उल्लेख किया है , तो आपको flushमैन्युअल रूप से कॉल करने की आवश्यकता नहीं होगी ।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.