Чому вам потрібно створити курсор під час запиту бази даних sqlite?


133

Я абсолютно новий в модулі sqlite3 Python (і взагалі SQL з цього приводу), і це мене абсолютно спотикає. Повна відсутність описів cursorпредметів (скоріше, їх необхідність) також здається дивним.

Цей фрагмент коду є бажаним способом вчинити:

import sqlite3
conn = sqlite3.connect("db.sqlite")
c = conn.cursor()
c.execute('''insert into table "users" values ("Jack Bauer", "555-555-5555")''')
conn.commit()
c.close()

Цей не є, хоча він працює так само добре і без (здавалося б, безглуздого) cursor:

import sqlite3
conn = sqlite3.connect("db.sqlite")
conn.execute('''insert into table "users" values ("Jack Bauer", "555-555-5555")''')
conn.commit()

Хто-небудь може сказати мені, навіщо мені потрібно cursor?
Це просто здається безглуздим накладним. Для кожного методу мого сценарію, який має доступ до бази даних, я повинен створити та знищити cursor?
Чому б просто не використовувати connectionоб’єкт?

Відповіді:


60

Мені здається просто неправильна абстракція. Курсор db - це абстракція, призначена для обходу набору даних.

З статті Вікіпедії на тему :

В інформатиці та техніці курсор бази даних - це керуюча структура, яка дозволяє переходити до записів у базі даних. Курсори полегшують подальшу обробку спільно з обходом, таким як пошук, додавання та видалення записів із бази даних. Курсор бази даних, характерний для обходу, робить курсори схожими на концепцію мови програмування ітератора.

І:

Курсори можна використовувати не тільки для отримання даних із СУБД у додаток, але й для виявлення рядка в таблиці, яку потрібно оновити чи видалити. Стандарт SQL: 2003 визначає позиційне оновлення та позиціонування видалення SQL-операторів для цієї мети. У таких висловлюваннях не використовується звичайний пункт WHERE з предикатами. Натомість курсор ідентифікує рядок. Курсор повинен бути відкритий і вже розміщений у рядку за допомогою оператора FETCH.

Якщо ви перевірите документи на модулі Python sqlite , ви зможете побачити, що модуль python cursorпотрібен навіть для CREATE TABLEоператора, тому він використовується у випадках, коли простого connectionоб'єкта має вистачити - як правильно вказано в ОП. Така абстракція відрізняється від того, що люди розуміють, що це курсор db, і, отже, плутанина / фрустрація з боку користувачів. Незалежно від ефективності, це лише концептуальні накладні витрати. Було б добре, якби в документах було зазначено, що модуль python cursorтрохи інший, ніж те, що курсор є в SQL та базах даних.


7
+1 за визнання (спочатку) дуже заплутаною відмінністю між "традиційними" db-курсорами та курсорами, які використовуються для db в Python
Пол Дрейпер


38

Для отримання результатів вам потрібен об’єкт курсору. Ваш приклад працює, тому що він є, INSERTі, отже, ви не намагаєтеся повернути з нього жодних рядків, але якщо ви подивитеся на sqlite3документи , ви помітите, що немає ніяких .fetchXXXXметодів на об'єктах підключення, тож якщо ви намагалися зробити a SELECTбез курсору ви не зможете отримати отримані дані.

Об'єкти курсору дозволяють вам відслідковувати, який набір результатів є, оскільки це можливо, щоб запустити кілька запитів, перш ніж закінчити отримання результатів першого.


5
Також варто пам’ятати: PEP 249 не визначає executeоб’єкт з'єднання, це sqlite3розширення.
Cat Plus Plus

4
Він як і раніше працює з операторами SELECT: pastebin.com/5ZbhfEn7 . Причина полягає в тому, що ви не викликаєте жодних методів .fetchXXXX на об’єкті з'єднання, ви викликаєте метод .fetchXXXX на об’єкті, повернутому методом .execute () з'єднання.
Джек Бауер

1
Так. Але один із способів у вас виявляється непотрібний курсор, за допомогою якого слід запитувати базу даних: p
Джек Бауер

2
Явно використовувати курсори - це хороша звичка вступати, оскільки, ймовірно, будуть майбутні проекти, над якими ви працюєте, де все не відбувається автоматично.
Бурштин

1
Досить справедливо. Дякую за інформацію :)
Джек Бауер

36

Згідно з офіційними документами connection.execute() , це нестандартний ярлик, який створює проміжний об'єкт курсору:

Connection.execute
Це нестандартний ярлик, який створює об'єкт курсору, викликаючи метод cursor (), викликає метод Execute () курсора із заданими параметрами та повертає курсор.


19

12.6.8. Використання ефективного sqlite3 ly

12.6.8.1. Використання ярликових методів

Використовуючи нестандартні execute() , executemany()і executescript()методи об'єкта Connection, ваш код може бути написаний більш коротким LY , тому що ви не повинні створювати (часто зайві ) Cursor об'єкти в явному вигляді. Натомість об'єкти Cursor створюються неявно, і ці способи швидкого доступу повертають об'єкти курсору. Таким чином, ви можете виконати оператор SELECT і повторити його безпосередньо, використовуючи лише один виклик об'єкта Connection.

( документація sqlite3 ; акцент на моєму.)

Чому б не просто використовувати об’єкт з'єднання?

Оскільки ці методи об'єкта з'єднання є нестандартними , тобто вони не є частиною специфікації API бази даних Python v2.0 (PEP 249).

Поки ви використовуєте стандартні методи об’єкта Cursor, ви можете бути впевнені, що якщо ви перейдете на іншу реалізацію бази даних, що відповідає вищевказаній специфікації, ваш код буде повністю переносним. Можливо, вам знадобиться лише змінитиimport лінію.

Але якщо ви використовуєте, connection.executeє ймовірність, що переключення не буде таким простим. Це основна причина, яку ви можете використовувати cursor.executeзамість цього.

Однак якщо ви впевнені, що не збираєтесь переходити, я б сказав, що цілком нормально приймати connection.executeярлик і бути "ефективним".


1

Це дає нам можливість мати кілька окремих робочих середовищ через одне і те ж підключення до бази даних.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.