2009-03-17 13 views
5

मैं लेन-देन डेटाबेस के लिए कुछ नया हूं और एक समस्या में आया हूं जिसे मैं समझने की कोशिश कर रहा हूं।पायथन पोस्टग्रेस कर्सर टाइमस्टैम्प समस्या

मैंने एक साधारण प्रदर्शन बनाया है जहां चेरीपी द्वारा बनाए गए प्रत्येक 5 धागे के अंदर डेटाबेस कनेक्शन संग्रहीत किया जाता है। मेरे पास एक विधि है जो डेटाबेस में संग्रहीत टाइमस्टैम्प की एक तालिका और टाइम स्टैंप का नया रिकॉर्ड जोड़ने के लिए एक बटन प्रदर्शित करती है।

तालिका में 2 फ़ील्ड हैं, एक datetime.datetime.now() के लिए एक पाइथन द्वारा पारित टाइमस्टैम्प और डेटाबेस टाइमस्टैम्प के लिए डिफ़ॉल्ट रूप से सेट()।


CREATE TABLE test (given_time timestamp, 
        default_time timestamp DEFAULT NOW()); 

मेरे पास 2 विधियां हैं जो डेटाबेस से बातचीत करती हैं। पहला नया कर्सर बनाएगा, एक नया दिया गया_टिमस्टैम्प डालें, कर्सर को प्रतिबद्ध करेगा, और इंडेक्स पेज पर वापस आ जाएगा। दूसरी विधि एक नया कर्सर बनाएगी, 10 सबसे हालिया टाइमस्टैम्प का चयन करें और कॉलर को वापस कर दें।


import sys 
import datetime 
import psycopg2 
import cherrypy 

def connect(thread_index): 
    # Create a connection and store it in the current thread 
    cherrypy.thread_data.db = psycopg2.connect('dbname=timestamps') 

# Tell CherryPy to call "connect" for each thread, when it starts up 
cherrypy.engine.subscribe('start_thread', connect) 

class Root: 
    @cherrypy.expose 
    def index(self): 
     html = [] 
     html.append("<html><body>") 

     html.append("<table border=1><thead>") 
     html.append("<tr><td>Given Time</td><td>Default Time</td></tr>") 
     html.append("</thead><tbody>") 

     for given, default in self.get_timestamps(): 
      html.append("<tr><td>%s<td>%s" % (given, default)) 

     html.append("</tbody>") 
     html.append("</table>") 

     html.append("<form action='add_timestamp' method='post'>") 
     html.append("<input type='submit' value='Add Timestamp'/>") 
     html.append("</form>") 

     html.append("</body></html>") 
     return "\n".join(html) 

    @cherrypy.expose 
    def add_timestamp(self): 
     c = cherrypy.thread_data.db.cursor() 
     now = datetime.datetime.now() 
     c.execute("insert into test (given_time) values ('%s')" % now) 
     c.connection.commit() 
     c.close() 
     raise cherrypy.HTTPRedirect('/') 

    def get_timestamps(self): 
     c = cherrypy.thread_data.db.cursor() 
     c.execute("select * from test order by given_time desc limit 10") 
     records = c.fetchall() 
     c.close() 
     return records 

if __name__ == '__main__': 

    cherrypy.config.update({'server.socket_host': '0.0.0.0', 
          'server.socket_port': 8081, 
          'server.thread_pool': 5, 
          'tools.log_headers.on': False, 
          }) 

    cherrypy.quickstart(Root()) 

मैं given_time और default_time timestamps केवल एक दूसरे से दूर कुछ माइक्रोसेकंड होने की अपेक्षा करेंगे। हालांकि मुझे कुछ अजीब व्यवहार मिल रहा है। यदि मैं प्रत्येक कुछ सेकंड में टाइमस्टैम्प जोड़ता हूं, तो डिफ़ॉल्ट_टाइम दिए गए समय से कुछ माइक्रोसेकंड नहीं है, लेकिन आमतौर पर पिछले दिए गए समय से कुछ माइक्रोसेकंड बंद हो जाता है।

 
Given Time     Default Time 
2009-03-18 09:31:30.725017 2009-03-18 09:31:25.218871 
2009-03-18 09:31:25.198022 2009-03-18 09:31:17.642010 
2009-03-18 09:31:17.622439 2009-03-18 09:31:08.266720 
2009-03-18 09:31:08.246084 2009-03-18 09:31:01.970120 
2009-03-18 09:31:01.950780 2009-03-18 09:30:53.571090 
2009-03-18 09:30:53.550952 2009-03-18 09:30:47.260795 
2009-03-18 09:30:47.239150 2009-03-18 09:30:41.177318 
2009-03-18 09:30:41.151950 2009-03-18 09:30:36.005037 
2009-03-18 09:30:35.983541 2009-03-18 09:30:31.666679 
2009-03-18 09:30:31.649717 2009-03-18 09:30:28.319693 

फिर भी, अगर मैं हर एक मिनट में के बारे में एक नया टाइमस्टैम्प जोड़ने के लिए, दोनों given_time और default_time केवल अपेक्षा के अनुरूप बंद कुछ माइक्रोसेकंड हैं। हालांकि, 6 वां टाइमस्टैम्प सबमिट करने के बाद (थ्रेड + 1 की संख्या) डिफ़ॉल्ट_टाइम पहले दिए गए टाइमटाम्प से कुछ माइक्रोसेकंड बंद है।

 
Given Time     Default Time 
2009-03-18 09:38:15.906788 2009-03-18 09:33:58.839075 
2009-03-18 09:37:19.520227 2009-03-18 09:37:19.520293 
2009-03-18 09:36:04.744987 2009-03-18 09:36:04.745039 
2009-03-18 09:35:05.958962 2009-03-18 09:35:05.959053 
2009-03-18 09:34:10.961227 2009-03-18 09:34:10.961298 
2009-03-18 09:33:58.822138 2009-03-18 09:33:55.423485 

हालांकि मैं स्पष्ट रूप से प्रत्येक उपयोग के बाद कर्सर को बंद कर रहा हूँ, ऐसा लगता है कि पिछले कर्सर अभी भी पुन: उपयोग किया जा रहा है। यह कैसे संभव है यदि मैं कर्सर को बंद कर रहा हूं और इसके बाद हर बार एक नया कर्सर बना रहा हूं? क्या कोई यहां बता सकता है कि यहां क्या हो रहा है? एक जवाब के लिए

करीब:

मैं एक cursor.connection.commit (जोड़ दिया है) get_timestamps विधि करने के लिए और कहा कि अब मुझे टाइमस्टैम्प के साथ सही आंकड़ा देता है। क्या कोई समझा सकता है कि मुझे कर्सर को कॉल करने की आवश्यकता क्यों हो सकती है .connection.commit() जब मैं बस इतना कर रहा हूं तो एक चयन है? मैं अनुमान लगा रहा हूं कि हर बार जब मैं कर्सर प्राप्त करता हूं, तो एक लेनदेन शुरू होता है (या मौजूदा लेनदेन इकाई के साथ जारी रहता है)। क्या ऐसा करने का कोई बेहतर तरीका है या क्या मैं हर बार कर्सर प्राप्त करता हूं, इस पर ध्यान दिए बिना कि मैं उस कर्सर के साथ क्या करता हूं?

उत्तर

1

सवाल अपने सबसे हाल ही संपादन से उत्पन्न समाधान करने के लिए:

PostgreSQL में, NOW() नहीं वर्तमान समय है, लेकिन समय वर्तमान लेन-देन के शुरू में। Psycopg2 शायद आपके लिए एक लेनदेन शुरू कर रहा है, और चूंकि लेनदेन कभी बंद नहीं होता है (एक प्रतिबद्धता या अन्यथा), टाइमस्टैम्प 'अटक गया' हो जाता है और बासी हो जाता है।

संभव फिक्स:

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

the manual, section 9.9.4 से, जोर कहा:

PostgreSQL कार्यों कि वर्तमान दिनांक और समय के लिए संबंधित मान के एक नंबर प्रदान करता है। ये एसक्यूएल मानक कार्यों सब मान वर्तमान लेन-देन की शुरुआत समय के आधार पर:

  • CURRENT_DATE
  • CURRENT_TIME
  • CURRENT_TIMESTAMP
  • CURRENT_TIME(precision)
  • CURRENT_TIMESTAMP(precision)
  • LOCALTIMELOCALTIMESTAMP
  • LOCALTIME(precision)
  • LOCALTIMESTAMP(precision)

CURRENT_TIME और CURRENT_TIMESTAMP समय क्षेत्र के साथ मूल्यों देने; LOCALTIME और LOCALTIMESTAMP समय क्षेत्र के बिना मूल्य प्रदान करते हैं।

CURRENT_TIME, CURRENT_TIMESTAMP, LOCALTIME, और LOCALTIMESTAMP वैकल्पिक रूप से एक सटीक पैरामीटर है, जिसकी वजह लिए परिणाम सेकंड क्षेत्र में है कि अधिक दशमलव अंक पूर्ण होना दिया जा सकता है। परिशुद्धता पैरामीटर के बिना, परिणाम पूर्ण उपलब्ध परिशुद्धता के लिए है।

...

के बाद से इन कार्यों लौट वर्तमान लेन-देन की शुरू करने का समय, उनके मूल्यों लेनदेन के दौरान बदल नहीं है। यह एक सुविधा माना जाता है: आशय एक एकल लेन-देन, "वर्तमान" समय की एक लगातार धारणा है करने के लिए इतना है कि कई संशोधनों ही लेन-देन के भीतर एक ही समय स्टाम्प सहन अनुमति है।

नोट: अन्य डेटाबेस सिस्टम इन मानों को और अधिक बार बढ़ा सकते हैं।

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

  • now()
  • transaction_timestamp()
  • statement_timestamp()
  • clock_timestamp()
  • timeofday()

now() एक पारंपरिक PostgreSQLहैCURRENT_TIMESTAMP के बराबर। transaction_timestamp() इसी प्रकार CURRENT_TIMESTAMP के समतुल्य है, लेकिन को स्पष्ट रूप से यह दर्शाता है कि यह रिटर्न देता है। statement_timestamp() वर्तमान कथन का प्रारंभ समय लौटाता है (अधिक विशेष रूप से, क्लाइंट से नवीनतम आदेश संदेश प्राप्त होने के समय )। statement_timestamp() और transaction_timestamp() के पहले आदेश के दौरान एक ही मान को वापस लेते हैं, लेकिन के बाद के आदेशों के दौरान भिन्न हो सकता है। clock_timestamp() वास्तविक वर्तमान समय देता है, और इसलिए इसकी मान एक एकल SQL कमांड के भीतर भी बदलती है। timeofday() एक ऐतिहासिक PostgreSQL फ़ंक्शन है। clock_timestamp() की तरह, यह वास्तविक वर्तमान समय देता है, लेकिन टाइम ज़ोन मान के साथ टाइमस्टैम्प की बजाय स्वरूपित टेक्स्ट स्ट्रिंग के रूप में देता है।

+0

इसे समझाने के लिए धन्यवाद। मैंने अभी तक आपके सुझावों का परीक्षण नहीं किया है, लेकिन मैंने यह बताने का सबसे अच्छा काम करने के लिए अपना जवाब स्वीकार कर लिया है कि टाइमस्टैम्प गलत क्यों होगा। हालांकि, अब मैं सोच रहा हूं कि कोई तरीका है कि मैं एक लेनदेन शुरू किए बिना कर्सर बना सकता हूं। – adam

+0

आप साइकोप 2 को लेनदेन अलगाव स्तर 'ISOLATION_LEVEL_AUTOCOMMIT' पर सेट कर सकते हैं, जो आदेश जारी किए जाने पर लेनदेन शुरू नहीं करेगा। मुझे नहीं पता कि परिवर्तन कितना व्यापक होगा, यद्यपि; ऐसा करने से लेन-देन का उपयोग करने वाले अन्य प्रश्नों को तोड़ सकता है। – kquinn

3

कोशिश बुला c.close() मॉड्यूल दस्तावेज़ में वर्णित: http://tools.cherrypy.org/wiki/Databases

def add_timestamp(self): 
     c = cherrypy.thread_data.db.cursor() 
     now = datetime.datetime.now() 
     c.execute("insert into test (given_time) values ('%s')" % now) 
     c.connection.commit() 
     c.close() 
     raise cherrypy.HTTPRedirect('/') 

def get_timestamps(self): 
     c = cherrypy.thread_data.db.cursor() 
     c.execute("select * from test order by given_time desc limit 10") 
     records = c.fetchall() 
     c.close() 
     return records 
+0

मैंने अभी उन परिवर्तन किए और चेरीपी सर्वर को पुनरारंभ किया और मुझे अभी भी एक ही समस्या है। – adam

+0

अद्यतन: हम पोस्टग्रेज़ 8.0 से 8.3 तक चले गए और यह उत्तर अब भी काम करता है। – adam

0

मैं जोड़ लिया है एक विधि है कि टाइम स्टाम्प्स का चयन करता है करने के लिए प्रतिबद्ध है और उस समस्या को हल किया है।

def get_timestamps(self): 
    c = cherrypy.thread_data.db.cursor() 
    c.execute("select * from test order by given_time desc limit 10") 
    records = c.fetchall() 
    c.connection.commit() # Adding this line fixes the timestamp issue 
    c.close() 
    return records 

किसी को भी कारण है कि मैं cursor.connection.commit (कॉल करने के लिए) की आवश्यकता होगी जब सभी मैं कर रहा हूँ एक चयन है व्याख्या कर सकते हैं?

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