Базы данных сами по себе редко эффективно управляются без помощи внешних систем. В реальных проектах одной базы данных и системы управления часто недостаточно. Общение с БД осуществляется через язык программирования, что позволяет более точно настраивать запросы и обрабатывать полученные ответы до дальнейших действий с ними. Императивные языки программирования имеют больше возможностей работы с данными, чем SQL, который является декларативным языком.
Каждый язык программирования и способ взаимодействия с БД обладает своими особенностями. Это включает в себя команды для подключения к БД, использование "курсоров", выполнение SQL-команд и сохранение изменений.
Инструменты для работы с определенной СУБД не встроены в сам язык и подключаются через модули или библиотеки. Модуль sqlite3 входит в стандартный пакет Python, не требуя отдельной установки, однако его все равно нужно импортировать:
>>> import sqlite3
Библиотека SQLite поставляется с Python. Модуль sqlite3 работает как интерфейс к СУБД SQLite, позволяя организовать взаимодействие на уровне Python-кода, преобразуя команды и ответы между форматами языков.
Этот модуль предлагает множество классов, функций и констант, доступных через функцию dir().
С помощью функции connect() создается экземпляр класса Connection, что связывает программу с файлом базы данных:
>>> db = sqlite3.connect('site.sqlite') >>> type(db) <class 'sqlite3.Connection'>
Для создания объекта через функцию, а не напрямую через класс, может существовать причина. Это позволяет обрабатывать дополнительные необязательные аргументы, например, имя базы данных. Полное описание функции connect() включает множество параметров:
sqlite3.connect(database[, timeout, detect_types, isolation_level, check_same_thread, factory, cached_statements, uri])
После создания объекта Connection для выполнения SQL-команд нужно создать объект класса Cursor через метод cursor() этого объекта:
SQL-команды выполняются с помощью метода execute(), а для удобного разделения длинных запросов можно использовать тройные кавычки. Рассмотрим пример создания таблиц:
>>> cur.execute('''CREATE TABLE sections ( ... _id INTEGER PRIMARY KEY, ... name TEXT)''' ...) <sqlite3.Cursor object at 0x7fd0f16fe110> >>> cur.execute('''CREATE TABLE pages ( ... _id INTEGER PRIMARY KEY AUTOINCREMENT, ... title TEXT, ... url TEXT NOT NULL, ... theme INTEGER NOT NULL, ... num INTEGER NOT NULL DEFAULT 100, ... FOREIGN KEY (theme) REFERENCES sections(_id)) ... ''') <sqlite3.Cursor object at 0x7fd0f16fe110>
Для активизации поддержки внешних ключей необходимо использовать специальную SQL-команду:
>>> cur.execute("PRAGMA foreign_keys = ON")
<sqlite3.Cursor object at 0x7fd0f16fe110>
Заметьте, что в данном примере SQL-запросы не оканчиваются точкой с запятой, и метод execute() возвращает сам объект курсора.
Для заполнения таблиц, если нужно вставить множество значений, удобнее использовать метод executemany():
>>> sections = [(1, 'Information'), (2, 'Digital Systems'), ... (3, 'Boolean Algebra')] >>> cur.executemany("INSERT INTO sections VALUES (?, ?)", sections) <sqlite3.Cursor object at 0x7fd0f16fe110>
Здесь создается список кортежей, и каждая запись представляет собой отдельную строку таблицы. Такой подход может использоваться и в методе execute():
>>> cur.execute("INSERT INTO sections VALUES (4, ?)", ('Algorithm',)) <sqlite3.Cursor object at 0x7fd0f16fe110>
Такой формат требует, чтобы передаваемые данные были кортежем. Значения вставляются на места знаков вопроса. Метод executescript() позволяет выполнить несколько SQL-запросов, завершенных точками с запятой, за один вызов.
Курсор поддерживает методы fetchone(), fetchmany() и fetchall(), которые извлекают данные при необходимости их получения. Эти методы дают возможность использовать курсор как объект-итератор:
>>> cur.execute("SELECT * FROM sections")
<sqlite3.Cursor object at 0x7fd0f16fe110>
>>> cur.fetchone()
(1, 'Information')
>>> cur.fetchone()
(2, 'Digital Systems')
>>> cur.__next__()
(3, 'Boolean Algebra')
Следующие примеры:
>>> cur.execute<("SELECT * FROM sections") >>> cur.fetchall() [(1, 'Information'), (2, 'Digital Systems'), (3, 'Boolean Algebra'), (4, 'Algorithm')] >>> cur.fetchall() [] >>> cur.execute("SELECT * FROM sections") <sqlite3.Cursor object at 0x7fd0f16fe110> >>> cur.fetchmany(2) [(1, 'Information'), (2, 'Digital Systems')] >>> cur.fetchmany(2) [(3, 'Boolean Algebra'), (4, 'Algorithm')] >>> cur.fetchmany(2) []
Чтобы завершить работу с базой данных должным образом, нужно сохранить изменения (при необходимости) и закрыть соединение. Эти операции выполняются через объект Connection:
>>> db.commit() >>> db.close()
Не использование commit() перед закрытием приведет к потере внесенных изменений. Для отмены изменений текущей сессии можно использовать метод rollback().
Вопросы для самопроверки:
- Какие функции и классы предлагает модуль sqlite3?
- Почему необходимо импортировать модуль sqlite3, если он входит в стандартную библиотеку Python?
- Как создать подключение к базе данных и зачем используется класс Connection?
- Какой метод позволяет выполнять несколько SQL-запросов одновременно и как он работает?
- Какие методы курсора помогают извлечь данные из результата SQL-запроса?
- Почему важно правильно завершать работу с базой данных, и какие методы для этого используются?