Python, SQLite3: курсор возвращает дубликаты, когда коммит вмешивается

Этот код Python создает таблицу, вставляет в нее три строки и выполняет итерацию по строкам с промежуточными фиксациями до того, как курсор полностью исчерпан. Почему он возвращает пять строк вместо трех? Если промежуточная фиксация удалена, количество возвращенных строк равно трем, как ожидалось. Или ожидалось, что фиксация (которая даже не касается этой таблицы) лишает значение курсора?

Изменить: добавлен забытый фиксатор (который заставляет проблему исчезнуть) и вставить в несвязанную таблицу (что снова заставляет проблему появляться).

#!/usr/bin/env python3 import sqlite3 as sq db = sq.connect(':memory:') db.execute('CREATE TABLE tbl (col INTEGER)') db.execute('CREATE TABLE tbl2 (col INTEGER)') db.executemany('INSERT INTO tbl (col) VALUES (?)', [(0,), (1,), (2,)]) db.commit() print('count=' + str(db.execute('SELECT count(*) FROM tbl').fetchone()[0])) # Read and print the values just inserted into tbl for col in db.execute('SELECT col FROM tbl'): print(col) db.execute('INSERT INTO tbl2 VALUES (?)', col) db.commit() print('count=' + str(db.execute('SELECT count(*) FROM tbl').fetchone()[0])) 

Выход:

 count=3 (0,) (1,) (0,) (1,) (2,) count=3 

Обычно, когда N строк вставлены, N + 2 строки возвращаются итератором, по-видимому, всегда с первыми двумя дублируемыми.

One Solution collect form web for “Python, SQLite3: курсор возвращает дубликаты, когда коммит вмешивается”

Ваш последующий комментарий меня беспокоил (особенно потому, что было ясно, что вы были правы). Поэтому я потратил некоторое время на изучение исходного кода в библиотеке python _sqlite.c ( https://svn.python.org/projects/python/trunk/Modules/_sqlite/ ).

Я думаю, проблема заключается в том, как объект sqlite Connection обрабатывает курсоры. Внутренне объекты Connection сохраняют список курсоров AND подготовленных операторов. Вложенный db.execute('INSERT ...') сбрасывает список подготовленных операторов, связанных с объектом Connection .

Решение состоит в том, чтобы не полагаться на автоматическое управление курсором метода shortcut execute () и явно ссылаться на текущий Cursor . Cursors сохраняют собственные подготовленные списки операторов, которые отделены от объектов Connection .

Вы можете явно создать курсор ИЛИ вызвать fetchall () для вызова db.execute (). Пример:

 import sqlite3 as sq db = sq.connect(':memory:') db.execute('CREATE TABLE tbl (col INTEGER)') db.execute('CREATE TABLE tbl2 (col INTEGER)') db.executemany('INSERT INTO tbl (col) VALUES (?)', [(0,), (1,), (2,)]) db.commit() print('count=' + str(db.execute('SELECT count(*) FROM tbl').fetchone()[0])) # Read and print the values just inserted into tbl for col in db.execute('SELECT col FROM tbl').fetchall(): print(col) db.execute('INSERT INTO tbl2 VALUES (?)', col) db.commit() print('count=' + str(db.execute('SELECT count(*) FROM tbl').fetchone()[0])) 

Ожидается выход:

 count=3 (0,) (1,) (2,) count=3 

Если метод fetchall() является недопустимым для памяти, вам может потребоваться вернуться к изоляции между двумя подключениями к базе данных ( https://www.sqlite.org/isolation.html ). Пример:

 db1 = sq.connect('temp.db') db1.execute('CREATE TABLE tbl (col INTEGER)') db1.execute('CREATE TABLE tbl2 (col INTEGER)') db1.executemany('INSERT INTO tbl (col) VALUES (?)', [(0,), (1,), (2,)]) db1.commit() print('count=' + str(db1.execute('SELECT count(*) FROM tbl').fetchone()[0])) db2 = sq.connect('temp.db') # Read and print the values just inserted into tbl for col in db1.execute('SELECT col FROM tbl').fetchall(): print(col) db2.execute('INSERT INTO tbl2 VALUES (?)', col) db2.commit() print('count=' + str(db1.execute('SELECT count(*) FROM tbl').fetchone()[0])) 
  • Как печать объекта приводит к другому результату, чем как str (), так и repr ()?
  • sqlite3.OperationalError: нет такого столбца:
  • Ошибка программирования: неверное количество подключений
  • Как удалить запись в Sqlite
  • sqlite3.OperationalError: рядом с «?»: синтаксическая ошибка
  • Заполнение базы данных SQLite3 из TXT-файла с помощью Python
  • параметр не поддерживается при вставке int в sqlite
  • Сравнение двух идентичных объектов в Python (2.7) возвращает False
  •  
    Interesting Posts for Van-Lav
    Python - лучший язык программирования в мире.