2011-06-09 17 views
34

मैं जो एक GORM cacheing समस्याक्या मुझे कभी भी गोरम में कॉल को बचाने के लिए स्पष्ट रूप से फ्लश करने की आवश्यकता है?

//begin with all book.status's as UNREAD 
Book.list().each { book.status = Status.READ ; book.save() } 

println (Book.findAllByStatus (Status.READ)) //will print an empty list 
println (Book.list().findAll (it.status == Status.READ)) // will print all books 

मैं नहीं समझ सकता क्यों पिछले दो प्रश्नों अलग परिणाम प्रदर्शित हो सकती इंगित करने के लिए प्रकट होता है एक अजीब स्थिति है।

हालांकि अगर मैं book.save (फ्लश: सत्य) का निम्नलिखित संशोधन करता हूं। दोनों प्रिंटलाइन विवरण सभी पुस्तकों को वापस कर देंगे।

मैं इस धारणा के तहत था कि यह एक ही आवेदन के भीतर आवश्यक नहीं था।

संदर्भ के लिए उपयोग किया जा रहा

  • डीबी: mysql
  • ग्रूवी: 1.7.10
  • Grails: 1.3.7

@ Hoàng Long

मेरी समस्या नीचे प्रदर्शित की गई है, मान लीजिए कि एक्शन 1/एक्शन 2 दोनों को कई बार बुलाया जाता है, कोई विशेष पैटर्न में

def action1 = { 
    Foo foo = Foo.get(params.id) 
    //... modify foo 
    foo.save() //if I flush here, it will be inefficient if action1 is called in sequence 
} 

def action2 = { 
    //if I flush here, it will be inefficient if action2 is called in sequence 
    List<Foo> foos = Foo.findAllByBar (params.bar) 
    //... do something with foos 
} 

एक समाधान एक ध्वज है जो action1 द्वारा निर्धारित और यदि आवश्यक हो फ्लश करने के लिए एक्शन 2 द्वारा किया जाता है के लिए किया जाएगा। मेरी समस्या यह है कि यह एक अत्यधिक जटिल समाधान है, जो स्केलेबल नहीं है क्योंकि डीबी कॉल की जटिलता बढ़ जाती है।

boolean isFlushed = true 

def action1 = { 
    Foo foo = Foo.get(params.id) 
    //... modify foo 
    foo.save() 
    isFlushed = false 
} 

def action2 = { 
    if (!isFlushed) { 
     //flush hibernate session here 
    } 
    List<Foo> foos = Foo.findAllByBar (params.bar) 
    //... do something with foos 
} 

उत्तर

30

आपके मामले में, पहला कथन खाली सूची लौटाता है क्योंकि यह डेटाबेस से डेटा पढ़ता है, लेकिन डेटा अभी तक नहीं है।

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

आम तौर पर, आपको हाइबरनेट को आपके लिए (अनुकूलन के लिए) काम करना चाहिए - जब तक आप चाहते हैं कि डेटा तुरंत जारी रहे।

पीटर लेडब्रूक के अनुसार:

Let Hibernate do it's job and only manually flush the session when you have to, or at least only at the end of a batch of updates. You should only really use if you're not seeing the data in the database when it should be there. I know that's a bit wishy-washy, but the circumstances when such action is necessary depend on the database implementation and other factors.

से GORM Gotchas - part 1

अद्यतन:

import org.hibernate.* 

class SomeController { 
    SessionFactory sessionFactory 

    def save = { 
    assert sessionFactory != null 

    // loop and save your books here 

    def hibSession = sessionFactory.getCurrentSession() 
    assert hibSession != null 
    hibSession.flush() 
    } 
} 
+0

पर्याप्त मेला। मेरे प्रश्न में मैंने जो उदाहरण दिया वह समस्या का एक आदर्श मामला था।हकीकत में प्रत्येक कॉल को बचाने के लिए() बाद में कौन से प्रश्नों का उपयोग किया जाएगा, इस बारे में अनजान है ... मैं हमेशा डर से बाहर (फ्लश: सच) का उपयोग नहीं करना चाहता, लेकिन मैं और क्या कर सकता हूं? – Akusete

+0

@ अकुसेते: आपके मामले में, क्या आप अंत में केवल फ्लश सत्र में हाइबरनेट को कॉल कर सकते हैं? –

+0

यह लिंक उपयोगी हो सकता है: http://grails.org/FAQ#Q:%20How%20can%20I%20flush%20a%20Hibernate%20session%20multiple%20times%20within%20my%20controller%3F –

7

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

डिफ़ॉल्ट रूप से यह "ऑटो" पर सेट है और इसका मतलब है कि प्रत्येक क्वेरी से पहले सत्र को फ्लश किया जाता है जो सीधे डीबी को हिट करता है (और शायद अन्य मामलों में भी)।उस स्थिति में आपका Foo.findAllByBar पहले सत्र को फ़्लश करना चाहिए (संभावित प्रदर्शन समस्या!) और डीबी से सही मान पढ़ें।

फ़्लशमोड के लिए दो अन्य मूल्य हैं और यदि आप उनमें से एक सेट करते हैं तो यह आपकी समस्याओं को समझाएगा। सबसे पहले "मैनुअल" जिसका अर्थ है कि आप मैन्युअल फ्लश सत्र (उदाहरण के साथ सहेजें (फ्लश: सत्य) का निर्णय लेते हैं)। यदि आप ऐसा नहीं करते हैं तो Foo.findAllByBar पुराने डीबी राज्य को पढ़ता है। दूसरा एक " प्रतिबद्ध" है जिसका अर्थ है कि प्रत्येक लेनदेन प्रतिबद्धता के साथ सत्र फ़्लश किया जाता है। यदि आप "ट्रांज़ेक्शन" grails में कथन का उपयोग करते हैं तो यह काफी आसान है।

संसाधन: http://schneide.wordpress.com/2011/03/08/the-grails-performance-switch-flush-modecommit/ http://docs.jboss.org/hibernate/entitymanager/3.5/reference/en/html/objectstate.html#d0e1215

40

Do I ever need to explicitly flush GORM save calls in grails?

संक्षेप में हाँ, जैसा कि आप अपने कोड में क्या कर रहे हैं आप वस्तु तुरंत उपयोग करना चाहते हैं।

मुझे एक ही समस्या का सामना करना पड़ा, इसलिए यह कुछ चीजें पढ़ने के बाद मुझे मिली तस्वीर है।

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

एनबी: मध्यम बार (द्वितीय स्तर कैश अक्षम है) क्योंकि कोई लेनदेन कोड नहीं है। without transaction without error

ऊपर एक ही कोड है, तो त्रुटि:

without transaction with error

लेकिन अगर आपके कार्रवाई व्यवहार विधि बुला रहा है या withTransaction साथ इनलाइन लेनदेन पैदा कर रही है (और मान कार्रवाई करने के लिए कॉल पूरा बिना किसी त्रुटि के)। with transaction without error

उपरोक्त कोड में त्रुटि है तो: with transaction with error

मुझे आशा है कि यह मदद करता है, लेकिन अगर मैं किसी भी गलती या, बड़ा बिंदु शामिल करने के लिए मुझे टिप्पणी मैं अपने चित्रों को अद्यतन करेगा याद किया।

+1

अच्छा स्पष्टीकरण! –

+0

यह महान, अच्छा ग्राफिक्स है! –

1

अतिरिक्त जानकारी के लिए, आप अपने डोमेन क्लास इवेंट्स (अद्यतन के बाद, अद्यतन करने से पहले, ect) में फ्लश या सहेजने (फ्लश: सत्य) का उपयोग नहीं कर सकते हैं, यह एक स्टैक ओवरफ़्लो त्रुटि का कारण बन जाएगा। हालांकि आप फ्लश के बिना save() का उपयोग कर सकते हैं।

gorm docs

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

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