SQLite и Python: полное руководство по встроенной базе данных

Пройдите тест, узнайте какой профессии подходите
Сколько вам лет
0%
До 18
От 18 до 24
От 25 до 34
От 35 до 44
От 45 до 49
От 50 до 54
Больше 55

Для кого эта статья:

  • Программисты и разработчики, заинтересованные в изучении SQLite и работы с базами данных в Python
  • Студенты и новички в программировании, желающие освоить создание веб-приложений с использованием баз данных
  • Профессиональные разработчики, ищущие оптимизацию и лучшие практики при работе с SQLite в своих проектах

    SQLite — незаменимый инструмент для программистов, нуждающихся в локальной базе данных без установки полноценной СУБД. Встроенный в Python модуль sqlite3 позволяет хранить данные в единственном файле, что идеально для мобильных приложений, прототипов и небольших проектов. Я пользуюсь им более 7 лет для разработки прототипов перед миграцией на "тяжелые" базы данных, и ни разу не пожалел. Готовы узнать, как SQLite может стать вашим надёжным спутником в разработке? Приступим к подробному разбору с примерами кода 🚀

Хотите освоить Python и разработку веб-приложений с интеграцией баз данных на профессиональном уровне? Курс Обучение Python-разработке от Skypro предлагает структурированный подход к изучению от основ до продвинутых тем, включая работу с SQLite и другими базами данных. Вы получите практические навыки от экспертов отрасли и создадите реальное веб-приложение для вашего портфолио, используя все изученные технологии. Начните свой путь к профессии Python-разработчика прямо сейчас!

Основы модуля sqlite3 в Python: настройка и подключение

SQLite — это встроенная библиотека для Python, что означает отсутствие необходимости установки дополнительных пакетов 🎯. Она входит в стандартную библиотеку Python, начиная с версии 2.5. Для начала работы достаточно импортировать модуль sqlite3:

Python
Скопировать код
import sqlite3

# Создание соединения с базой данных (или создание новой, если не существует)
connection = sqlite3.connect('example.db')

# Создание курсора для выполнения SQL-команд
cursor = connection.cursor()

# После выполнения всех операций не забудьте закрыть соединение
connection.close()

Ключевые компоненты при работе с sqlite3:

  • Соединение (Connection) — представляет базу данных. Создаётся с помощью функции connect().
  • Курсор (Cursor) — объект, через который выполняются SQL-запросы.
  • Транзакция — группа SQL-команд, которые выполняются как единое целое.

При подключении к базе данных вы можете использовать несколько параметров:

Python
Скопировать код
# Подключение к базе в памяти (исчезает при закрытии соединения)
conn_memory = sqlite3.connect(':memory:')

# Автоматическая фиксация изменений (обычно не рекомендуется)
conn_autocommit = sqlite3.connect('example.db', isolation_level=None)

# Установка таймаута в секундах при блокировке базы
conn_timeout = sqlite3.connect('example.db', timeout=10.0)

# Преобразование строк в байты для поддержки не-ASCII символов
conn_text = sqlite3.connect('example.db', detect_types=sqlite3.PARSE_DECLTYPES)

Для безопасного закрытия соединения лучше использовать контекстный менеджер with:

Python
Скопировать код
with sqlite3.connect('example.db') as connection:
cursor = connection.cursor()
# Выполняйте операции с базой данных
# Соединение будет автоматически закрыто по окончании блока with

SQLite поддерживает несколько типов данных:

Тип SQLite Тип Python Описание
NULL None Отсутствие значения
INTEGER int Целочисленный тип
REAL float Числа с плавающей точкой
TEXT str Текстовые строки
BLOB bytes Бинарные данные

SQLite автоматически преобразует типы данных между Python и базой данных, но иногда может потребоваться явное указание типов, особенно для дат или специфичных объектов.

Александр Сомов, Python-разработчик с опытом более 8 лет

Работая над проектом для метеорологической станции, я столкнулся с необходимостью хранить миллионы записей температурных показателей в условиях ограниченных ресурсов на удаленном устройстве. PostgreSQL был слишком "тяжелым", а для MySQL требовалась дополнительная настройка сервера.

Решение пришло неожиданно — SQLite с модулем sqlite3. Первые тесты показали, что база отлично справляется с записью до 500 измерений в секунду, что более чем покрывало наши потребности. Самым приятным сюрпризом стала надежность: при внезапном отключении электричества (частое явление на удаленных станциях) база данных не теряла целостность.

Ключом к успеху стало правильное использование транзакций: мы объединяли множество операций записи в одну транзакцию, что не только ускоряло работу в 20 раз, но и обеспечивало атомарность операций. Проект работает уже третий год без единого сбоя базы данных. SQLite оказался не просто "легким решением" — это был оптимальный выбор.

Пошаговый план для смены профессии

Создание таблиц и структуры базы данных через Python

Создание таблиц в SQLite через Python происходит с помощью стандартного SQL-синтаксиса, который выполняется через объект курсора. Давайте рассмотрим базовые приемы создания и модификации структуры базы данных 📊.

Создание простой таблицы:

Python
Скопировать код
import sqlite3

with sqlite3.connect('store.db') as conn:
cursor = conn.cursor()

# Создание таблицы с товарами
cursor.execute('''
CREATE TABLE IF NOT EXISTS products (
id INTEGER PRIMARY KEY,
name TEXT NOT NULL,
price REAL NOT NULL,
category TEXT,
in_stock INTEGER DEFAULT 0
)
''')

# Сохранение изменений
conn.commit()

Обратите внимание на использование IF NOT EXISTS — это позволяет избежать ошибки, если таблица уже существует. При создании таблицы мы определяем структуру данных:

  • Имя столбца
  • Тип данных (INTEGER, TEXT, REAL, BLOB, NULL)
  • Ограничения (PRIMARY KEY, NOT NULL, UNIQUE, DEFAULT и т.д.)

SQLite поддерживает несколько типов ограничений для обеспечения целостности данных:

Python
Скопировать код
# Таблица с различными ограничениями
cursor.execute('''
CREATE TABLE customers (
id INTEGER PRIMARY KEY AUTOINCREMENT,
email TEXT UNIQUE NOT NULL,
name TEXT NOT NULL,
age INTEGER CHECK(age >= 18),
registration_date TEXT DEFAULT CURRENT_TIMESTAMP,
status TEXT DEFAULT 'active'
)
''')

Для организации связей между таблицами используются внешние ключи. По умолчанию SQLite не проверяет их целостность, поэтому необходимо включить проверку:

Python
Скопировать код
# Включение проверки внешних ключей
cursor.execute('PRAGMA foreign_keys = ON')

# Создание таблицы с внешним ключом
cursor.execute('''
CREATE TABLE orders (
id INTEGER PRIMARY KEY,
customer_id INTEGER,
order_date TEXT DEFAULT CURRENT_TIMESTAMP,
total_amount REAL NOT NULL,
FOREIGN KEY (customer_id) REFERENCES customers(id)
)
''')

Для изменения структуры существующей таблицы используются команды ALTER TABLE:

Python
Скопировать код
# Добавление нового столбца
cursor.execute('ALTER TABLE products ADD COLUMN description TEXT')

# Переименование таблицы (SQLite имеет ограниченную поддержку ALTER TABLE)
cursor.execute('ALTER TABLE products RENAME TO items')

SQLite имеет ограниченную поддержку ALTER TABLE по сравнению с другими СУБД. Для более сложных изменений структуры часто используется следующий подход:

Python
Скопировать код
# Переименование старой таблицы
cursor.execute('ALTER TABLE products RENAME TO products_old')

# Создание новой таблицы с нужной структурой
cursor.execute('''
CREATE TABLE products (
id INTEGER PRIMARY KEY,
name TEXT NOT NULL,
price REAL NOT NULL,
category TEXT,
in_stock INTEGER DEFAULT 0,
supplier_id INTEGER
)
''')

# Копирование данных из старой таблицы
cursor.execute('''
INSERT INTO products (id, name, price, category, in_stock)
SELECT id, name, price, category, in_stock FROM products_old
''')

# Удаление старой таблицы
cursor.execute('DROP TABLE products_old')

Для удаления таблиц используется команда DROP TABLE:

Python
Скопировать код
# Удаление таблицы
cursor.execute('DROP TABLE IF EXISTS temporary_data')

Создание индексов помогает ускорить выборку данных:

Python
Скопировать код
# Создание индекса для повышения производительности поиска по категории
cursor.execute('CREATE INDEX idx_products_category ON products(category)')

# Создание уникального индекса
cursor.execute('CREATE UNIQUE INDEX idx_customers_email ON customers(email)')

SQLite поддерживает различные типы индексов:

Тип индекса Команда создания Когда использовать
Обычный индекс CREATE INDEX Для ускорения поиска по столбцам с множеством запросов
Уникальный индекс CREATE UNIQUE INDEX Для обеспечения уникальности значений в столбце
Составной индекс CREATE INDEX ON table(col1, col2) Для запросов, использующих несколько столбцов
Частичный индекс CREATE INDEX ON table(col) WHERE condition Для индексирования только подмножества строк

CRUD операции в sqlite3: практическое руководство с кодом

CRUD (Create, Read, Update, Delete) операции — фундаментальные действия при работе с любой базой данных. Рассмотрим, как выполнять их с помощью модуля sqlite3 в Python 🔄.

1. Создание (Create) — добавление данных

Существует несколько способов вставки данных в таблицу:

Python
Скопировать код
import sqlite3

with sqlite3.connect('store.db') as conn:
cursor = conn.cursor()

# Вставка одной записи
cursor.execute(
"INSERT INTO products (name, price, category, in_stock) VALUES (?, ?, ?, ?)",
("Laptop XPS 13", 1299.99, "Electronics", 10)
)

# Получение ID последней вставленной записи
last_id = cursor.lastrowid
print(f"Добавлен товар с ID: {last_id}")

# Вставка нескольких записей (executemany)
products = [
("Smartphone Galaxy S21", 899.99, "Electronics", 15),
("Headphones HD-100", 149.99, "Audio", 25),
("Coffee Maker Pro", 79.99, "Home Appliances", 5)
]
cursor.executemany(
"INSERT INTO products (name, price, category, in_stock) VALUES (?, ?, ?, ?)",
products
)

# Фиксация изменений
conn.commit()

Важно: Всегда используйте параметризованные запросы (?) вместо прямой подстановки значений, чтобы избежать SQL-инъекций.

2. Чтение (Read) — получение данных

SQLite предлагает различные способы получения данных из таблицы:

Python
Скопировать код
# Получение всех записей
cursor.execute("SELECT * FROM products")
all_products = cursor.fetchall()

# Получение записей с фильтрацией
cursor.execute("SELECT id, name, price FROM products WHERE category = ? AND price < ?", 
("Electronics", 1000))
electronics_under_1000 = cursor.fetchall()

# Получение одной записи
cursor.execute("SELECT * FROM products WHERE id = ?", (1,))
product = cursor.fetchone()

# Получение ограниченного числа записей
cursor.execute("SELECT * FROM products ORDER BY price DESC")
top_5_expensive = cursor.fetchmany(5)

# Итерирование по результатам запроса
cursor.execute("SELECT * FROM products")
for product in cursor:
print(product)

Результаты запросов возвращаются в виде кортежей. Для удобства можно использовать Row factory, который позволяет обращаться к полям по именам:

Python
Скопировать код
conn.row_factory = sqlite3.Row
cursor = conn.cursor()
cursor.execute("SELECT * FROM products WHERE id = ?", (1,))
product = cursor.fetchone()
print(f"Name: {product['name']}, Price: {product['price']}")

3. Обновление (Update) — изменение данных

Обновление существующих записей выполняется с помощью SQL-команды UPDATE:

Python
Скопировать код
# Обновление одной записи
cursor.execute(
"UPDATE products SET price = ?, in_stock = ? WHERE id = ?",
(1199.99, 8, 1)
)

# Обновление нескольких записей
cursor.execute(
"UPDATE products SET category = ? WHERE category = ?",
("Smartphones", "Mobile Phones")
)

# Инкремент/декремент значений
cursor.execute("UPDATE products SET in_stock = in_stock – 1 WHERE id = ?", (1,))

# Проверка количества обновленных строк
rows_affected = cursor.rowcount
print(f"Обновлено записей: {rows_affected}")

conn.commit()

4. Удаление (Delete) — стирание данных

Удаление записей производится с помощью команды DELETE:

Python
Скопировать код
# Удаление одной записи
cursor.execute("DELETE FROM products WHERE id = ?", (3,))

# Удаление нескольких записей с условием
cursor.execute("DELETE FROM products WHERE category = ? AND in_stock = 0", ("Electronics",))

# Очистка всей таблицы (осторожно!)
cursor.execute("DELETE FROM products")

# Более эффективный способ очистки таблицы
cursor.execute("DROP TABLE IF EXISTS products")
cursor.execute('''CREATE TABLE products (
id INTEGER PRIMARY KEY,
name TEXT NOT NULL,
price REAL NOT NULL,
category TEXT,
in_stock INTEGER DEFAULT 0
)''')

conn.commit()

Мария Коваленко, инженер по данным

В один из дней мне поступил срочный запрос от отдела продаж: нужно было разработать инструмент для анализа истории продаж с возможностью быстрого внесения корректировок. Срок — два дня, и система должна работать на любом компьютере без установки дополнительного ПО.

Я решила использовать Python с SQLite. Создала простую структуру базы данных с таблицами для клиентов, товаров и транзакций. Самой сложной частью оказалась обработка множественных CRUD-операций с сохранением целостности данных.

Ключевым моментом стало использование транзакций и параметризованных запросов:

Python
Скопировать код
try:
cursor.execute("BEGIN TRANSACTION")

for sale in sales_data:
# Обновление остатков товара
cursor.execute(
"UPDATE products SET stock = stock – ? WHERE id = ?",
(sale['quantity'], sale['product_id'])
)

# Проверка доступности товара
cursor.execute(
"SELECT stock FROM products WHERE id = ?",
(sale['product_id'],)
)
remaining = cursor.fetchone()[0]

if remaining < 0:
raise Exception(f"Недостаточно товара (ID: {sale['product_id']})")

# Запись продажи
cursor.execute(
"INSERT INTO sales (product_id, customer_id, quantity, price) VALUES (?, ?, ?, ?)",
(sale['product_id'], sale['customer_id'], sale['quantity'], sale['price'])
)

cursor.execute("COMMIT")
except Exception as e:
cursor.execute("ROLLBACK")
print(f"Ошибка: {e}")

Этот подход гарантировал, что либо все операции выполнятся успешно, либо ни одна не будет применена. Проект был сдан вовремя, и сейчас система обрабатывает около 5000 операций ежедневно без единого сбоя. Весь код занял менее 300 строк, но полностью решил проблему отдела.

Продвинутые SQL-запросы и функции модуля sqlite3

После освоения базовых CRUD операций, пора погрузиться в более сложные возможности SQLite через Python. Эти продвинутые техники позволят вам максимально эффективно использовать базу данных в ваших проектах 💪.

1. Сложные запросы и объединение таблиц

SQLite поддерживает различные виды объединений таблиц:

Python
Скопировать код
# INNER JOIN – только записи с совпадениями в обеих таблицах
cursor.execute('''
SELECT o.id, c.name as customer, o.order_date, o.total_amount 
FROM orders o
INNER JOIN customers c ON o.customer_id = c.id
WHERE o.total_amount > 100
ORDER BY o.order_date DESC
''')

# LEFT JOIN – все записи из левой таблицы и совпадающие из правой
cursor.execute('''
SELECT p.name as product, c.name as category, p.price 
FROM products p
LEFT JOIN categories c ON p.category_id = c.id
''')

# Подзапросы
cursor.execute('''
SELECT name, price FROM products 
WHERE price > (SELECT AVG(price) FROM products)
''')

# Агрегирование данных
cursor.execute('''
SELECT category, COUNT(*) as product_count, AVG(price) as avg_price 
FROM products 
GROUP BY category
HAVING COUNT(*) > 1
ORDER BY avg_price DESC
''')

2. Транзакции для обеспечения целостности данных

Транзакции гарантируют, что либо все операции внутри транзакции выполнятся, либо ни одна из них:

Python
Скопировать код
# Начало транзакции
conn.execute("BEGIN TRANSACTION")

try:
# Уменьшаем количество товара на складе
cursor.execute("UPDATE products SET in_stock = in_stock – ? WHERE id = ?", (1, 1))

# Проверяем, что не ушли в отрицательное значение
cursor.execute("SELECT in_stock FROM products WHERE id = ?", (1,))
current_stock = cursor.fetchone()[0]

if current_stock < 0:
# Если что-то пошло не так, отменяем все изменения
conn.rollback()
print("Недостаточно товара на складе")
else:
# Добавляем запись о продаже
cursor.execute('''
INSERT INTO sales (product_id, quantity, sale_date)
VALUES (?, ?, datetime('now'))
''', (1, 1))
# Фиксируем изменения
conn.commit()
print("Продажа завершена успешно")
except Exception as e:
conn.rollback()
print(f"Ошибка: {e}")

3. Пользовательские функции и агрегаты

SQLite позволяет создавать собственные функции на Python для использования в SQL-запросах:

Python
Скопировать код
# Определение пользовательской функции
def levenshtein_distance(s1, s2):
# Реализация алгоритма расстояния Левенштейна
# для нечеткого поиска
if len(s1) < len(s2):
return levenshtein_distance(s2, s1)
if len(s2) == 0:
return len(s1)

previous_row = range(len(s2) + 1)
for i, c1 in enumerate(s1):
current_row = [i + 1]
for j, c2 in enumerate(s2):
insertions = previous_row[j + 1] + 1
deletions = current_row[j] + 1
substitutions = previous_row[j] + (c1 != c2)
current_row.append(min(insertions, deletions, substitutions))
previous_row = current_row

return previous_row[-1]

# Регистрация функции в SQLite
conn.create_function("levenshtein", 2, levenshtein_distance)

# Использование в запросе для нечеткого поиска
search_term = "labtop"
cursor.execute('''
SELECT id, name, price, levenshtein(name, ?) as distance
FROM products
WHERE distance <= 3
ORDER BY distance
''', (search_term,))

# Регистрация агрегатной функции
class MedianAggregate:
def __init__(self):
self.values = []

def step(self, value):
if value is not None:
self.values.append(value)

def finalize(self):
if not self.values:
return None
self.values.sort()
n = len(self.values)
if n % 2 == 0:
return (self.values[n//2-1] + self.values[n//2]) / 2
else:
return self.values[n//2]

conn.create_aggregate("median", 1, MedianAggregate)

# Использование агрегатной функции
cursor.execute("SELECT category, median(price) FROM products GROUP BY category")

4. Обработка больших объемов данных

Для эффективной работы с большими наборами данных можно использовать следующие техники:

Python
Скопировать код
# Использование генераторов для обработки больших выборок
cursor.execute("SELECT * FROM log_entries WHERE date > ?", ('2023-01-01',))
for row in cursor: # использование итератора, не загружает все в память
process_log_entry(row)

# Пакетная обработка при вставке
big_data = [(f"Item {i}", random.uniform(10, 1000), random.choice(categories), random.randint(1, 100)) 
for i in range(10000)]

# Вставка большого объема данных с использованием транзакции
conn.execute("BEGIN TRANSACTION")
try:
# Вставка блоками по 1000 записей
for i in range(0, len(big_data), 1000):
chunk = big_data[i:i+1000]
cursor.executemany(
"INSERT INTO products (name, price, category, in_stock) VALUES (?, ?, ?, ?)",
chunk
)
conn.commit()
except Exception as e:
conn.rollback()
print(f"Ошибка: {e}")

5. Работа с бинарными данными (BLOB)

SQLite позволяет хранить бинарные данные, например, изображения или файлы:

Python
Скопировать код
# Сохранение изображения в базу данных
with open('product_image.jpg', 'rb') as file:
image_data = file.read()
cursor.execute(
"UPDATE products SET image = ? WHERE id = ?",
(sqlite3.Binary(image_data), 1)
)

# Извлечение изображения из базы
cursor.execute("SELECT image FROM products WHERE id = ?", (1,))
image_data = cursor.fetchone()[0]
with open('retrieved_image.jpg', 'wb') as file:
file.write(image_data)

6. Работа с датами и временем

SQLite не имеет специального типа для дат, но предоставляет функции для их обработки:

Python
Скопировать код
# Текущая дата и время в формате ISO
cursor.execute("SELECT datetime('now')")
current_time = cursor.fetchone()[0]

# Добавление интервалов к датам
cursor.execute("SELECT datetime('now', '+1 day', '+2 hours')")

# Поиск записей за последнюю неделю
cursor.execute('''
SELECT * FROM orders 
WHERE order_date >= datetime('now', '-7 days')
''')

# Форматирование дат
cursor.execute("SELECT strftime('%Y-%m-%d', order_date) as day, COUNT(*) as orders FROM orders GROUP BY day")

Эти продвинутые техники сделают ваши приложения более мощными и эффективными при работе с данными в SQLite.

Оптимизация и лучшие практики при работе с SQLite в Python

Правильная оптимизация SQLite может значительно повысить производительность вашего приложения. В этом разделе я поделюсь проверенными на практике стратегиями и лучшими практиками для эффективной работы с SQLite в Python 🚀.

1. Оптимизация производительности запросов

  • Используйте индексы для часто запрашиваемых столбцов — это значительно ускорит поиск и сортировку
  • Избегайте SELECT * — запрашивайте только необходимые столбцы
  • Используйте EXPLAIN QUERY PLAN — для анализа эффективности запроса
Python
Скопировать код
# Анализ плана выполнения запроса
cursor.execute("EXPLAIN QUERY PLAN SELECT * FROM products WHERE category = 'Electronics'")
for row in cursor.fetchall():
print(row)

# Создание индекса для оптимизации
cursor.execute("CREATE INDEX IF NOT EXISTS idx_products_category ON products(category)")

# Повторный анализ запроса с индексом
cursor.execute("EXPLAIN QUERY PLAN SELECT * FROM products WHERE category = 'Electronics'")

2. Настройка конфигурации SQLite для оптимальной производительности

Python
Скопировать код
# Установка параметров pragma для повышения производительности
cursor.execute("PRAGMA synchronous = NORMAL") # Default: FULL
cursor.execute("PRAGMA journal_mode = WAL") # Default: DELETE
cursor.execute("PRAGMA cache_size = -64000") # ~64MB cache (negative means kibibytes)
cursor.execute("PRAGMA temp_store = MEMORY") # Store temp tables in memory
cursor.execute("PRAGMA mmap_size = 30000000000") # Use memory-mapped I/O when possible

Важнейшие настройки PRAGMA для оптимизации:

Параметр Рекомендуемое значение Описание Когда применять
journal_mode WAL Write-Ahead Logging — повышает конкурентность и производительность Для большинства приложений
synchronous NORMAL Баланс между безопасностью и скоростью Когда небольшая потеря данных допустима
cache_size -64000 (64MB) Больший кеш ускоряет операции На машинах с достаточной памятью
temp_store MEMORY Временные таблицы в памяти Для сложных запросов с временными таблицами
mmap_size 30000000000 Использование memory-mapping для чтения Для больших баз данных с преимущественно чтением

3. Эффективная работа с транзакциями

Правильное использование транзакций может дать огромный прирост производительности:

Python
Скопировать код
# Без транзакции: медленно при множестве операций
for i in range(10000):
cursor.execute("INSERT INTO log VALUES (?, ?)", (i, f"Log entry {i}))
conn.commit() # Каждая транзакция вызывает запись на диск

# С транзакцией: намного быстрее
cursor.execute("BEGIN TRANSACTION")
for i in range(10000):
cursor.execute("INSERT INTO log VALUES (?, ?)", (i, f"Log entry {i}))
conn.commit() # Только одна запись на диск

4. Предотвращение утечек ресурсов

Убедитесь, что ресурсы SQLite правильно освобождаются:

  • Используйте контекстный менеджер with для автоматического закрытия соединения
  • Закрывайте курсоры после использования
  • Освобождайте ресурсы в блоках try-finally
Python
Скопировать код
# Безопасное использование ресурсов
def process_data():
try:
conn = sqlite3.connect('database.db')
cursor = conn.cursor()
# ... операции с базой данных
return results
except Exception as e:
print(f"Ошибка: {e}")
raise
finally:
if cursor:
cursor.close()
if conn:
conn.close()

# Альтернатива с использованием with
def better_process_data():
with sqlite3.connect('database.db') as conn:
cursor = conn.cursor()
try:
# ... операции с базой данных
return results
finally:
cursor.close()

5. Многопоточная и многопроцессная работа

SQLite поддерживает множественные подключения для чтения, но только одно для записи. При работе с потоками учитывайте:

Python
Скопировать код
import threading
import queue

# Пример многопоточной работы с SQLite
def worker(job_queue, results_queue):
# Каждый поток должен иметь своё соединение
with sqlite3.connect('database.db') as conn:
conn.row_factory = sqlite3.Row
cursor = conn.cursor()

while True:
try:
job = job_queue.get(timeout=1)
if job == "STOP":
break

# Выполнение запроса
cursor.execute("SELECT * FROM products WHERE id = ?", (job,))
result = dict(cursor.fetchone())
results_queue.put(result)

except queue.Empty:
break
finally:
job_queue.task_done()

# Запуск пула потоков
job_queue = queue.Queue()
results_queue = queue.Queue()

# Добавляем задания
for i in range(1, 101):
job_queue.put(i)

# Запускаем потоки
threads = []
for i in range(4): # 4 параллельных потока
t = threading.Thread(target=worker, args=(job_queue, results_queue))
t.start()
threads.append(t)

# Дожидаемся завершения и собираем результаты
job_queue.join()
for t in threads:
job_queue.put("STOP")

for t in threads:
t.join()

results = []
while not results_queue.empty():
results.append(results_queue.get())

6. Безопасность и защита данных

Защитите свою базу данных от атак и повреждений:

  • Всегда используйте параметризованные запросы для защиты от SQL-инъекций
  • Создавайте регулярные резервные копии базы данных
  • Проверяйте целостность базы данных периодически
  • Используйте шифрование для защиты чувствительных данных
Python
Скопировать код
# Проверка целостности базы данных
cursor.execute("PRAGMA integrity_check")
integrity_result = cursor.fetchone()[0]
if integrity_result != "ok":
print(f"Проблема с целостностью базы: {integrity_result}")

# Резервное копирование базы данных
import shutil
from datetime import datetime

def backup_database(db_path):
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
backup_path = f"{db_path}.backup_{timestamp}"

# Для безопасного копирования сначала создаём соединение в режиме только для чтения
with sqlite3.connect(f"file:{db_path}?mode=ro", uri=True) as conn:
# Принудительно записываем все изменения на диск
conn.execute("PRAGMA wal_checkpoint(FULL)")

# Копируем файл базы данных
shutil.copy2(db_path, backup_path)

# Копируем файлы журнала, если используется режим WAL
wal_file = f"{db_path}-wal"
shm_file = f"{db_path}-shm"

if os.path.exists(wal_file):
shutil.copy2(wal_file, f"{backup_path}-wal")
if os.path.exists(shm_file):
shutil.copy2(shm_file, f"{backup_path}-shm")

return backup_path

# Пример использования шифрования с pysqlcipher3 (требуется установка)
# pip install pysqlcipher3
def encrypt_sensitive_data():
from pysqlcipher3 import dbapi2 as sqlcipher

# Соединение с зашифрованной базой данных
conn = sqlcipher.connect('encrypted.db')
cursor = conn.cursor()

# Установка ключа шифрования
cursor.execute("PRAGMA key='your_strong_password'")

# Дальнейшие операции с базой данных...

7. Мониторинг и отладка

Для отслеживания производительности и поиска узких мест:

Python
Скопировать код
# Включение профилировщика запросов
def profile_queries(conn):
queries = []

def trace_callback(query):
queries.append(query)

conn.set_trace_callback(trace_callback)
return queries

# Использование профилировщика
with sqlite3.connect('database.db') as conn:
queries = profile_queries(conn)

# Выполняем операции
conn.execute("SELECT * FROM products")
conn.execute("UPDATE products SET price = price * 1.1 WHERE category = 'Electronics'")

# Анализируем выполненные запросы
for i, query in enumerate(queries, 1):
print(f"Запрос {i}: {query}")

# Настройка журналирования SQLite
import logging

# Настройка логгера
logging.basicConfig(
level=logging.DEBUG,
format='%(asctime)s – %(name)s – %(levelname)s – %(message)s',
filename='sqlite_debug.log'
)

# Перехват сообщений из SQLite
def sql_trace_callback(statement):
logging.debug(f"SQL: {statement}")

conn.set_trace_callback(sql_trace_callback)

Следование этим лучшим практикам поможет создавать более быстрые, надежные и безопасные приложения с использованием SQLite и Python.

SQLite в Python — мощный инструмент для создания локальных баз данных, предлагающий идеальный баланс между простотой использования и функциональностью. Изучив основы подключения, создания структуры данных, выполнения CRUD-операций, а также продвинутые техники оптимизации, вы теперь готовы интегрировать полноценную базу данных в свои проекты. Помните, что правильное использование индексов, транзакций и параметризованных запросов является ключом к созданию эффективных и безопасных приложений. Не бойтесь экспериментировать — SQLite прощает ошибки и позволяет легко начать заново, что делает его идеальной площадкой для оттачивания навыков работы с базами данных.

Загрузка...