Tôi hơi mới đối với cơ sở dữ liệu giao dịch và đã gặp một vấn đề mà tôi đang cố gắng hiểu.python postgres pointer timestamp issue
Tôi đã tạo một cuộc biểu tình đơn giản trong đó kết nối cơ sở dữ liệu được lưu trữ bên trong mỗi trong số 5 luồng được tạo bởi cherrypy. Tôi có một phương pháp hiển thị một bảng các dấu thời gian được lưu trữ trong cơ sở dữ liệu và một nút để thêm một bản ghi thời gian mới.
bảng có 2 trường, một cho dấu thời gian datetime.datetime.now() được chuyển bởi python và một cho dấu thời gian cơ sở dữ liệu được đặt thành mặc định NOW().
CREATE TABLE test (given_time timestamp,
default_time timestamp DEFAULT NOW());
Tôi có 2 phương pháp tương tác với cơ sở dữ liệu. Việc đầu tiên sẽ tạo ra một con trỏ mới, chèn một given_timestamp mới, cam kết con trỏ và trở về trang chỉ mục. Phương pháp thứ hai sẽ tạo ra một con trỏ mới, chọn 10 dấu thời gian gần đây nhất và trả về dấu thời gian cho người gọi.
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())
Tôi hy vọng dấu thời gian given_time và default_time chỉ cách nhau một vài micro giây. Tuy nhiên tôi nhận được một số hành vi kỳ lạ. Nếu tôi thêm dấu thời gian vài giây một lần, default_time không phải là một vài micro giây so với given_time, nhưng thường là một vài micro giây từ trước đó given_time.
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
Tuy nhiên, nếu tôi thêm dấu thời gian mới khoảng một lần một phút, cả thời gian đã cho và thời gian mặc định chỉ là một vài giây như mong đợi. Tuy nhiên, sau khi gửi dấu thời gian thứ 6 (số lượng các chủ đề + 1) default_time là một vài micro giây tắt từ dấu thời gian given_time đầu tiên.
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
Mặc dù tôi rõ ràng đóng con trỏ sau mỗi lần sử dụng, dường như con trỏ trước đó vẫn đang được sử dụng lại. Làm thế nào là có thể nếu tôi đóng con trỏ sau khi tôi hoàn thành nó và tạo một con trỏ mới mỗi lần? Ai đó có thể giải thích những gì đang diễn ra ở đây không?
Closer to một câu trả lời:
Tôi đã thêm một cursor.connection.commit() để phương pháp get_timestamps và bây giờ mang lại cho tôi dữ liệu chính xác với timestamps. Bất cứ ai có thể giải thích tại sao tôi có thể cần phải gọi cursor.connection.commit() khi tất cả tôi đang làm là một lựa chọn? Tôi đoán rằng mỗi khi tôi nhận được một con trỏ, một giao dịch bắt đầu (hoặc tiếp tục với một đơn vị giao dịch hiện tại nó được cam kết). Có cách nào tốt hơn để làm điều này hoặc tôi bị mắc kẹt cam kết mỗi khi tôi nhận được một con trỏ bất kể những gì tôi làm với con trỏ đó?
Cảm ơn bạn đã giải thích điều này. Tôi chưa thử nghiệm các đề xuất của bạn, nhưng tôi đã chấp nhận câu trả lời của bạn để thực hiện công việc tốt nhất để giải thích lý do tại sao dấu thời gian sẽ không chính xác. Tuy nhiên, bây giờ tôi tự hỏi nếu có một cách tôi có thể tạo ra một con trỏ mà không cần bắt đầu một giao dịch. – adam
Bạn có thể đặt Psycopg2 thành mức cô lập giao dịch 'ISOLATION_LEVEL_AUTOCOMMIT', sẽ không bắt đầu giao dịch khi lệnh được phát hành. Tuy nhiên, tôi không biết sự thay đổi rộng lớn như thế nào; làm như vậy có thể phá vỡ các truy vấn khác sử dụng giao dịch. – kquinn