Я несколько новичок в транзакционных базах данных и столкнулся с проблемой, которую пытаюсь понять.
Я создал простую демонстрацию, где соединение с базой данных хранится в каждом из 5 потоков, созданных cherrypy. У меня есть метод, который отображает таблицу отметок времени, хранящихся в базе данных, и кнопку для добавления новой записи отметок времени.
таблица имеет 2 поля, одно для метки времени datetime.datetime.now (), переданной python, и одно для метки времени базы данных, установленной по умолчанию NOW ().
CREATE TABLE test (given_time timestamp,
default_time timestamp DEFAULT NOW());
У меня есть 2 метода, которые взаимодействуют с базой данных. Первый создаст новый курсор, вставит новый Given_timestamp, зафиксирует курсор и вернется на страницу индекса. Второй метод создаст новый курсор, выберет 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())
Я бы ожидал, что отметки времени данного времени и значения по умолчанию будут на расстоянии всего лишь нескольких микросекунд друг от друга. Однако я получаю странное поведение. Если я добавляю временные метки каждые несколько секунд, default_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
Тем не менее, если я добавляю новую временную метку примерно раз в минуту, то данный момент и время по умолчанию на несколько микросекунд отключены, как и ожидалось. Однако после отправки 6-й отметки времени (количество потоков + 1) значение default_time составляет несколько микросекунд с момента первой отметки времени данного времени.
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, и теперь он дает мне точные данные с отметками времени. Может кто-нибудь объяснить, почему мне нужно вызывать cursor.connection.commit (), когда все, что я делаю, это выбор? Я предполагаю, что каждый раз, когда я получаю курсор, транзакция начинается (или продолжается с существующей единицей транзакции, которую она фиксирует). Есть ли лучший способ сделать это, или я застреваю, фиксируя каждый раз, когда я получаю курсор, независимо от того, что я делаю с этим курсором?