数据库编程基础:SQLite3、CRUD与参数化查询
数据库编程基础:SQLite3、CRUD与参数化查询
数据库是现代应用的核心组件,用于持久化存储和管理数据。Python内置了sqlite3模块,让我们无需安装额外软件就能学习数据库编程。本文将从基础开始,带你掌握数据库操作的核心技能。
SQLite简介
SQLite是一个轻量级的嵌入式数据库,不需要服务器进程,数据存储在单个文件中。它是Python内置的,非常适合学习和小型应用。
import sqlite3
# 连接数据库(不存在则自动创建)
conn = sqlite3.connect("example.db")
# 获取游标对象
cursor = conn.cursor()
# 执行SQL语句
cursor.execute("SELECT sqlite_version()")
# 获取结果
version = cursor.fetchone()
print(f"SQLite版本: {version[0]}")
# 关闭连接
conn.close()
创建表
import sqlite3
conn = sqlite3.connect("school.db")
cursor = conn.cursor()
# 创建学生表
cursor.execute("""
CREATE TABLE IF NOT EXISTS students (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL,
age INTEGER,
grade TEXT,
score REAL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
)
""")
# 创建课程表
cursor.execute("""
CREATE TABLE IF NOT EXISTS courses (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL,
teacher TEXT,
credits INTEGER DEFAULT 3
)
""")
# 创建选课表(多对多关系)
cursor.execute("""
CREATE TABLE IF NOT EXISTS enrollments (
id INTEGER PRIMARY KEY AUTOINCREMENT,
student_id INTEGER,
course_id INTEGER,
grade TEXT,
FOREIGN KEY (student_id) REFERENCES students(id),
FOREIGN KEY (course_id) REFERENCES courses(id)
)
""")
# 提交事务
conn.commit()
conn.close()
CRUD操作
创建(Create)
import sqlite3
conn = sqlite3.connect("school.db")
cursor = conn.cursor()
# 插入单条记录
cursor.execute("""
INSERT INTO students (name, age, grade, score)
VALUES (?, ?, ?, ?)
""", ("张三", 20, "A", 85.5))
# 获取刚插入的ID
student_id = cursor.lastrowid
print(f"插入的学生ID: {student_id}")
# 插入多条记录
students = [
("李四", 21, "B", 78.0),
("王五", 19, "A", 92.5),
("赵六", 22, "C", 65.0),
("钱七", 20, "B", 88.0)
]
cursor.executemany("""
INSERT INTO students (name, age, grade, score)
VALUES (?, ?, ?, ?)
""", students)
# 插入课程数据
courses = [
("Python编程", "张老师", 4),
("数据库原理", "李老师", 3),
("计算机网络", "王老师", 3)
]
cursor.executemany("""
INSERT INTO courses (name, teacher, credits)
VALUES (?, ?, ?)
""", courses)
conn.commit()
print(f"插入了 {cursor.rowcount} 条记录")
conn.close()
读取(Read)
import sqlite3
conn = sqlite3.connect("school.db")
cursor = conn.cursor()
# 查询所有记录
cursor.execute("SELECT * FROM students")
all_students = cursor.fetchall()
for student in all_students:
print(student)
# 查询单条记录
cursor.execute("SELECT * FROM students WHERE name = ?", ("张三",))
student = cursor.fetchone()
print(f"找到学生: {student}")
# 查询多条记录
cursor.execute("SELECT * FROM students WHERE score > ?", (80,))
good_students = cursor.fetchall()
print(f"成绩大于80的学生: {len(good_students)} 人")
# 条件查询
cursor.execute("""
SELECT name, age, score
FROM students
WHERE age >= 20 AND grade IN ('A', 'B')
ORDER BY score DESC
""")
results = cursor.fetchall()
for name, age, score in results:
print(f"{name} ({age}岁) - 成绩: {score}")
# 聚合查询
cursor.execute("""
SELECT
COUNT(*) as total,
AVG(score) as avg_score,
MAX(score) as max_score,
MIN(score) as min_score
FROM students
""")
stats = cursor.fetchone()
print(f"总人数: {stats[0]}, 平均分: {stats[1]:.1f}")
更新(Update)
import sqlite3
conn = sqlite3.connect("school.db")
cursor = conn.cursor()
# 更新单条记录
cursor.execute("""
UPDATE students
SET score = ?, grade = ?
WHERE name = ?
""", (95.0, "A+", "张三"))
print(f"更新了 {cursor.rowcount} 条记录")
# 批量更新
cursor.execute("""
UPDATE students
SET score = score + 5
WHERE score < 60
""")
print(f"加分了 {cursor.rowcount} 名学生")
# 条件更新
cursor.execute("""
UPDATE students
SET grade = CASE
WHEN score >= 90 THEN 'A'
WHEN score >= 80 THEN 'B'
WHEN score >= 70 THEN 'C'
WHEN score >= 60 THEN 'D'
ELSE 'F'
END
""")
conn.commit()
conn.close()
删除(Delete)
import sqlite3
conn = sqlite3.connect("school.db")
cursor = conn.cursor()
# 删除单条记录
cursor.execute("DELETE FROM students WHERE name = ?", ("赵六",))
print(f"删除了 {cursor.rowcount} 条记录")
# 批量删除
cursor.execute("DELETE FROM students WHERE score < 60")
# 清空表
cursor.execute("DELETE FROM students") # 保留表结构
# 或者
# cursor.execute("DROP TABLE students") # 删除表
conn.commit()
conn.close()
参数化查询与防SQL注入
import sqlite3
def safe_query(conn, query, params=None):
"""安全的查询封装"""
cursor = conn.cursor()
try:
if params:
cursor.execute(query, params)
else:
cursor.execute(query)
return cursor.fetchall()
except sqlite3.Error as e:
print(f"查询错误: {e}")
return []
conn = sqlite3.connect("school.db")
# 正确:使用参数化查询
name = "张三"
cursor = conn.cursor()
cursor.execute("SELECT * FROM students WHERE name = ?", (name,))
result = cursor.fetchone()
# 错误:字符串拼接(易受SQL注入攻击)
# cursor.execute(f"SELECT * FROM students WHERE name = '{name}'") # 不要这样做!
# 动态构建查询
def dynamic_search(conn, **kwargs):
"""动态条件搜索"""
conditions = []
params = []
for key, value in kwargs.items():
if value is not None:
conditions.append(f"{key} = ?")
params.append(value)
if not conditions:
return []
where_clause = " AND ".join(conditions)
query = f"SELECT * FROM students WHERE {where_clause}"
return safe_query(conn, query, params)
# 使用动态搜索
results = dynamic_search(conn, grade="A", age=20)
print(f"搜索结果: {len(results)} 条")
conn.close()
事务管理
import sqlite3
conn = sqlite3.connect("school.db")
try:
# 开始事务(sqlite3默认自动开启)
cursor = conn.cursor()
# 执行多个操作
cursor.execute("""
INSERT INTO students (name, age, grade, score)
VALUES (?, ?, ?, ?)
""", ("新学生", 20, "A", 85))
student_id = cursor.lastrowid
cursor.execute("""
INSERT INTO enrollments (student_id, course_id)
VALUES (?, ?)
""", (student_id, 1))
# 提交事务
conn.commit()
print("事务提交成功")
except sqlite3.Error as e:
# 发生错误,回滚事务
conn.rollback()
print(f"事务回滚: {e}")
finally:
conn.close()
# 使用上下文管理器
with sqlite3.connect("school.db") as conn:
conn.execute("PRAGMA foreign_keys = ON")
cursor = conn.cursor()
# 使用with语句自动提交/回滚
with conn:
cursor.execute("""
INSERT INTO students (name, age, grade, score)
VALUES (?, ?, ?, ?)
""", ("自动提交学生", 19, "B", 78))
连接池与性能优化
import sqlite3
from contextlib import contextmanager
class Database:
def __init__(self, db_path):
self.db_path = db_path
@contextmanager
def connection(self):
"""获取数据库连接的上下文管理器"""
conn = sqlite3.connect(self.db_path)
conn.row_factory = sqlite3.Row # 使用字典式访问
try:
yield conn
finally:
conn.close()
def execute(self, query, params=None):
with self.connection() as conn:
cursor = conn.cursor()
if params:
cursor.execute(query, params)
else:
cursor.execute(query)
return cursor.fetchall()
def executemany(self, query, params_list):
with self.connection() as conn:
cursor = conn.cursor()
cursor.executemany(query, params_list)
conn.commit()
def fetch_one(self, query, params=None):
results = self.execute(query, params)
return results[0] if results else None
# 使用示例
db = Database("school.db")
# 使用Row工厂可以按列名访问
results = db.execute("SELECT * FROM students WHERE grade = ?", ("A",))
for row in results:
print(f"{row['name']}: {row['score']}")
# 批量插入
data = [("学生" + str(i), 20, "A", 80 + i) for i in range(10)]
db.executemany("""
INSERT INTO students (name, age, grade, score)
VALUES (?, ?, ?, ?)
""", data)
实战示例:图书管理系统
import sqlite3
from datetime import datetime
class BookDB:
def __init__(self, db_path="library.db"):
self.db_path = db_path
self.init_db()
def init_db(self):
with sqlite3.connect(self.db_path) as conn:
conn.execute("""
CREATE TABLE IF NOT EXISTS books (
id INTEGER PRIMARY KEY AUTOINCREMENT,
title TEXT NOT NULL,
author TEXT NOT NULL,
isbn TEXT UNIQUE,
quantity INTEGER DEFAULT 1,
available INTEGER DEFAULT 1
)
""")
conn.execute("""
CREATE TABLE IF NOT EXISTS borrowings (
id INTEGER PRIMARY KEY AUTOINCREMENT,
book_id INTEGER,
borrower TEXT,
borrow_date TIMESTAMP,
return_date TIMESTAMP,
FOREIGN KEY (book_id) REFERENCES books(id)
)
""")
def add_book(self, title, author, isbn, quantity=1):
with sqlite3.connect(self.db_path) as conn:
conn.execute("""
INSERT INTO books (title, author, isbn, quantity, available)
VALUES (?, ?, ?, ?, ?)
""", (title, author, isbn, quantity, quantity))
def borrow_book(self, book_id, borrower):
with sqlite3.connect(self.db_path) as conn:
book = conn.execute(
"SELECT available FROM books WHERE id = ?", (book_id,)
).fetchone()
if book and book[0] > 0:
conn.execute("""
INSERT INTO borrowings (book_id, borrower, borrow_date)
VALUES (?, ?, ?)
""", (book_id, borrower, datetime.now()))
conn.execute("""
UPDATE books SET available = available - 1
WHERE id = ?
""", (book_id,))
return True
return False
def return_book(self, book_id):
with sqlite3.connect(self.db_path) as conn:
conn.execute("""
UPDATE borrowings
SET return_date = ?
WHERE book_id = ? AND return_date IS NULL
""", (datetime.now(), book_id))
conn.execute("""
UPDATE books SET available = available + 1
WHERE id = ?
""", (book_id,))
# 使用示例
db = BookDB()
db.add_book("Python编程", "张三", "978-1234567890", 5)
db.add_book("数据库原理", "李四", "978-0987654321", 3)
db.borrow_book(1, "王五")
总结
数据库编程是后端开发的核心技能。掌握SQLite后,可以轻松过渡到MySQL、PostgreSQL等更强大的数据库系统。始终使用参数化查询防止SQL注入,合理使用事务保证数据一致性,并考虑使用ORM(如SQLAlchemy)来简化复杂操作。