2009-01-10 15 views
12

में ट्रांज़ेक्शन परिणामों के साथ उपयोग करके बहुत सारे डेटा डालने का मैं Grails 1.1 beta2 का उपयोग कर रहा हूं। मुझे अपने Grails आवेदन में बड़ी मात्रा में डेटा आयात करने की जरूरत है। यदि मैं बार-बार एक ग्रेल्स डोमेन क्लास को तुरंत चालू करता हूं और फिर इसे सहेजता हूं, तो प्रदर्शन अस्वीकार्य रूप से धीमा होता है। उदाहरण के लिए फोन बुक से लोगों को आयात करना:Grails, OutOfMemoryError

for (each person in legacy phone book) { 
    // Construct new Grails domain class from legacy phone book person 
    Person person = new Person(...) 
    person.save() 
} 

यह दर्दनाक रूप से धीमा हो जाता है। Grails मेलिंग सूची पर कोई सुझाव है कि बैचिंग एक लेनदेन में बचाता है। तो अब मेरे पास है:

List batch = new ArrayList() 
for (each person in legacy phone book) { 
    // Construct new Grails domain class from legacy phone book person 
    Person person = new Person(...) 
    batch.add(person) 
    if (batch.size() > 500) { 
     Person.withTransaction { 
      for (Person p: batch) 
       p.save() 
      batch.clear() 
     } 
    } 
} 
// Save any remaining 
for (Person p: batch) 
    p.save() 

यह काम शुरू में कम से कम तेज़ होना चाहिए। प्रत्येक लेनदेन 500 रिकॉर्ड बचाता है। जैसे ही समय चल रहा है, लेन-देन लंबे और लंबे समय तक लगते हैं। पहले कुछ लेन-देन में लगभग 5 सेकंड लगते हैं, फिर यह वहां से निकलता है। लगभग 100 लेनदेन के बाद, प्रत्येक एक मिनट से अधिक समय लेता है, जो एक बार फिर अस्वीकार्य है। इससे भी बदतर यह है कि आखिरकार Grails जावा हीप मेमोरी से बाहर चला जाएगा। मैं जेवीएम ढेर आकार बढ़ा सकता हूं, लेकिन यह OutOfMemoryError अपवाद में देरी करता है।

कोई विचार यह क्यों है? ऐसा लगता है कि कुछ आंतरिक संसाधन जारी नहीं किए जा रहे हैं। प्रदर्शन खराब हो जाता है, स्मृति जारी की जा रही है, और अंत में सिस्टम स्मृति से बाहर हो जाता है।

Grails documentation के अनुसार, withTransaction स्प्रिंग के TransactionStatus ऑब्जेक्ट को बंद कर देता है। लेनदेन को बंद/समाप्त करने के लिए मुझे TransactionStatus में कुछ भी नहीं मिला।

संपादित करें: मैं Grails 'कंसोल से चल रहा हूँ (grails console)

संपादित करें: यहाँ स्मृति अपवाद से बाहर बताया गया है:

Exception thrown: Java heap space 

java.lang.OutOfMemoryError: Java heap space 
    at org.hibernate.util.IdentityMap.entryArray(IdentityMap.java:194) 
    at org.hibernate.util.IdentityMap.concurrentEntries(IdentityMap.java:59) 
    at org.hibernate.event.def.AbstractFlushingEventListener.prepareEntityFlushes(AbstractFlushingEventListener.java:113) 
    at org.hibernate.event.def.AbstractFlushingEventListener.flushEverythingToExecutions(AbstractFlushingEventListener.java:65) 
    at org.hibernate.event.def.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:26) 
    at org.hibernate.impl.SessionImpl.flush(SessionImpl.java:1000) 
    at org.hibernate.impl.SessionImpl.managedFlush(SessionImpl.java:338) 
    at org.hibernate.transaction.JDBCTransaction.commit(JDBCTransaction.java:106) 
    at org.springframework.orm.hibernate3.HibernateTransactionManager.doCommit(HibernateTransactionManager.java:655) 
    at org.springframework.transaction.support.AbstractPlatformTransactionManager.processCommit(AbstractPlatformTransactionManager.java:732) 
    at org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:701) 
    at org.springframework.transaction.support.TransactionTemplate.execute(TransactionTemplate.java:140) 
+0

क्या संदर्भ में यह निष्पादित किया जा रहा है? एक क्वार्ट्ज नौकरी? एक नियंत्रक? जब हमने एक नियंत्रक का उपयोग कर अतीत में ऐसा किया है, तो हमें एक लूप सेट करने की इजाजत दी गई है जो बैचिंग आकार को बाध्य कर सकती है, सेवा में बाद के लेनदेन के आकार के साथ संगत –

उत्तर

12

यह सब हाइबरनेट साथ एक आम मुद्दा है अनुप्रयोगों और यह हाइबरनेट सत्र के विकास के कारण होता है। मैं अनुमान लगा रहा हूं कि grails कंसोल आपके लिए 'ओपन सत्र इन व्यू' पैटर्न के समान तरीके से एक हाइबरनेट सत्र खोलता है जिसे मैं जानता हूं कि यह सामान्य वेब अनुरोधों के लिए उपयोग करता है।

समाधान वर्तमान सत्र को पकड़ने और प्रत्येक बैच के बाद इसे साफ़ करने का है। मुझे यकीन नहीं है कि आप कंसोल का उपयोग करके वसंत बीन को कैसे पकड़ते हैं, आमतौर पर नियंत्रकों या सेवाओं के लिए आप उन्हें सदस्यों के रूप में घोषित करते हैं। फिर आप वर्तमान सत्र sessionFactory.getCurrentSession() के साथ प्राप्त कर सकते हैं। इसे साफ़ करने के लिए बस session.clear() पर कॉल करें, या यदि आप प्रत्येक Person ऑब्जेक्ट के लिए session.evict(Object) चुनिंदा उपयोग करना चाहते हैं।

एक नियंत्रक/सेवा के लिए

:

class FooController { 
    def sessionFactory 

    def doStuff = { 
     List batch = new ArrayList() 
     for (each person in legacy phone book) { 
      // Construct new Grails domain class from legacy phone book person 
      Person person = new Person(...) 
      batch.add(person) 
      if (batch.size() > 500) { 
       Person.withTransaction { 
        for (Person p: batch) 
         p.save() 
        batch.clear() 
       } 
       // clear session here. 
       sessionFactory.getCurrentSession().clear(); 
      } 
     } 
     // Save any remaining 
     for (Person p: batch) 
      p.save() 
     } 
    } 
} 

आशा इस मदद करता है।

+0

मैं session.clear() का उपयोग करके उस कोड को बेहतर बनाउंगा। लूप का प्रत्येक एन-वें पुनरावृत्ति, प्रत्येक नहीं। –

+0

पूरी तरह से सहमत हैं ... अब उस कोड को देखकर मुझे यकीन नहीं है कि यह भी काम करता है। –

15

टेड Naleid बैच के प्रदर्शन में सुधार के बारे में great blog entry लिखा था। एक संदर्भ के रूप में यहां शामिल है।