
🔎大家好,我是ZTLJQ,希望你看完之后,能对你有所帮助,不足请指正!共同学习交流
📝个人主页-ZTLJQ的主页
🎁欢迎各位→点赞👍 + 收藏⭐️ + 留言📝📣系列果你对这个系列感兴趣的话
专栏 - Python从零到企业级应用:短时间成为市场抢手的程序员
✔说明⇢本人讲解主要包括Python爬虫、JS逆向、Python的企业级应用
如果你对这个系列感兴趣的话,可以关注订阅哟👋
数据存储的基石
在现代应用程序中,数据是核心资产。无论是用户的个人信息、电子商务的订单记录,还是社交媒体的动态,这些有价值的信息都需要一个可靠、高效的地方进行存储、检索和管理。关系型数据库(Relational Database Management System, RDBMS)凭借其严格的数据结构、强大的查询能力和ACID事务特性,成为了绝大多数应用的首选。
对于Python开发者而言,掌握如何与关系型数据库交互是一项至关重要的技能。本篇博客将从数据库基础讲起,深入探讨Python中操作数据库的各种方式,从直接的SQL执行到高级的对象关系映射(ORM),并结合实际案例,带您构建一个完整的数据驱动应用。
第一部分:关系型数据库核心概念
在深入代码之前,我们需要理解关系型数据库的基本构成要素。
- 数据库 (Database): 一个容器,用于存储相关的数据集合。
- 表 (Table): 数据以表格形式存储,类似于Excel电子表格。表由行(记录)和列(字段)组成。
- 行 (Row/Record): 表中的一条数据记录。例如,用户表中的一行代表一个用户。
- 列 (Column/Field): 定义了数据的属性。例如,用户表中的"姓名"、"邮箱"列。
- 主键 (Primary Key): 一个或一组列,其值能够唯一标识表中的每一行。例如,用户ID。
- 外键 (Foreign Key): 一个表中的列,其值对应另一个表的主键,用于建立表与表之间的关系。例如,订单表中的"用户ID"列是用户表的外键。
- SQL (Structured Query Language) : 结构化查询语言,是与关系型数据库通信的标准语言。通过SQL,我们可以创建表(
CREATE TABLE)、插入数据(INSERT)、查询数据(SELECT)、更新数据(UPDATE)和删除数据(DELETE)。
第二部分:Python原生数据库连接------sqlite3
sqlite3模块是Python标准库的一部分,它提供了对SQLite数据库的原生接口。SQLite是一个轻量级的、无服务器的数据库,非常适合嵌入式应用、移动应用和小型Web项目。
2.1 实战案例:使用sqlite3构建一个图书管理系统
让我们从最基础的方式开始,使用sqlite3模块来创建一个简单的图书管理系统。
第一步:连接数据库并创建表
python
import sqlite3
# 连接到数据库 (如果文件不存在,会自动创建)
conn = sqlite3.connect('library.db')
# 创建一个游标对象,用于执行SQL命令
cursor = conn.cursor()
# 定义创建表的SQL语句
create_table_sql = '''
CREATE TABLE IF NOT EXISTS books (
id INTEGER PRIMARY KEY AUTOINCREMENT,
title TEXT NOT NULL,
author TEXT NOT NULL,
isbn TEXT UNIQUE,
published_year INTEGER,
genre TEXT
);
'''
# 执行SQL命令
cursor.execute(create_table_sql)
# 提交事务,确保更改被保存到数据库
conn.commit()
print("Database and table created successfully!")
代码解析:
sqlite3.connect('library.db'): 连接到名为library.db的数据库文件。如果文件不存在,SQLite会自动创建它。cursor.execute(sql): 游标对象是执行SQL命令的媒介。execute方法用于执行单条SQL语句。PRIMARY KEY AUTOINCREMENT: 指定id列为主键,并且它的值由数据库自动递增生成。UNIQUE: 约束isbn列的值必须是唯一的。conn.commit(): 非常重要!对数据库的任何修改(INSERT, UPDATE, DELETE)都必须通过commit()来提交事务,否则更改不会被永久保存。
第二步:插入数据
python
# 插入单条记录
insert_sql = '''
INSERT INTO books (title, author, isbn, published_year, genre)
VALUES (?, ?, ?, ?, ?)
'''
# 使用参数化查询,可以有效防止SQL注入攻击
book_data = ("The Great Gatsby", "F. Scott Fitzgerald", "978-0-7432-7356-5", 1925, "Fiction")
cursor.execute(insert_sql, book_data)
# 插入多条记录
more_books = [
("1984", "George Orwell", "978-0-452-28423-4", 1949, "Dystopian Fiction"),
("Pride and Prejudice", "Jane Austen", "978-0-14-143951-8", 1813, "Romance"),
("To Kill a Mockingbird", "Harper Lee", "978-0-06-112008-4", 1960, "Fiction")
]
cursor.executemany(insert_sql, more_books)
conn.commit()
print("Books inserted successfully!")
代码解析:
?是参数占位符。在执行SQL时,?会被execute方法的第二个参数(一个元组)中的值替换。这比直接拼接字符串安全得多。executemany(): 用于高效地执行同一条SQL语句多次,适用于批量插入数据。
第三步:查询数据
python
# 查询所有书籍
select_all_sql = "SELECT * FROM books;"
cursor.execute(select_all_sql)
all_books = cursor.fetchall()
print("\nAll Books:")
for book in all_books:
print(f"ID: {book[0]}, Title: {book[1]}, Author: {book[2]}")
# 查询特定条件的书籍
select_by_author_sql = "SELECT * FROM books WHERE author = ?;"
cursor.execute(select_by_author_sql, ("George Orwell",))
orwell_books = cursor.fetchall()
print("\nBooks by George Orwell:")
for book in orwell_books:
print(f"- {book[1]} ({book[3]})") # book[1]是标题, book[3]是年份
# 查询并获取单条记录
select_one_sql = "SELECT * FROM books WHERE title LIKE ?;"
cursor.execute(select_one_sql, ("%Pride%",))
one_book = cursor.fetchone()
if one_book:
print(f"\nFound one book matching 'Pride': {one_book[1]}")
代码解析:
fetchall(): 获取所有查询结果,返回一个元组列表。fetchone(): 获取查询结果的下一行,如果没有更多行,则返回None。LIKE '%Pride%': SQL中的模糊查询,%是通配符,表示任意字符。
第四步:更新和删除数据
python
# 更新数据
update_sql = "UPDATE books SET genre = ? WHERE title = ?;"
cursor.execute(update_sql, ("Classic Literature", "1984"))
conn.commit()
print("\nBook '1984' genre updated.")
# 删除数据
delete_sql = "DELETE FROM books WHERE title = ?;"
cursor.execute(delete_sql, ("To Kill a Mockingbird",))
conn.commit()
print("Book 'To Kill a Mockingbird' deleted.")
# 再次查询所有书籍以验证更改
cursor.execute("SELECT * FROM books;")
remaining_books = cursor.fetchall()
print("\nRemaining Books after deletion:")
for book in remaining_books:
print(f"ID: {book[0]}, Title: {book[1]}, Author: {book[2]}")
# 最后,关闭游标和连接
cursor.close()
conn.close()
代码解析:
UPDATE和DELETE语句同样需要WHERE子句来指定操作的目标,否则会更新或删除所有行。cursor.close()和conn.close()是良好的编程习惯,用于释放数据库连接资源。
第三部分:高级抽象------对象关系映射(ORM)与SQLAlchemy
直接使用SQL虽然灵活,但当项目变得复杂时,手动编写和管理SQL语句会变得繁琐且容易出错。**对象关系映射(Object-Relational Mapping, ORM)**技术应运而生。它允许我们用Python类来定义数据库表结构,用类的实例来表示表中的记录,从而可以用面向对象的方式来操作数据库。
SQLAlchemy (pip install sqlalchemy) 是Python中最强大、最灵活的ORM库。
3.1 实战案例:使用SQLAlchemy重写图书管理系统
我们将用SQLAlchemy来重构上面的图书管理系统。
第一步:定义模型
python
from sqlalchemy import create_engine, Column, Integer, String
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker
# 创建一个基类,我们的模型将继承自这个基类
Base = declarative_base()
# 定义Book模型类
class Book(Base):
__tablename__ = 'books' # 指定对应的数据库表名
id = Column(Integer, primary_key=True, autoincrement=True)
title = Column(String, nullable=False)
author = Column(String, nullable=False)
isbn = Column(String, unique=True)
published_year = Column(Integer)
genre = Column(String)
def __repr__(self):
return f"<Book(title='{self.title}', author='{self.author}')>"
代码解析:
declarative_base(): SQLAlchemy的声明式基类,所有模型类都要继承它。__tablename__: 类变量,定义了该模型映射到的数据库表的名称。Column(...): 定义了表中的列。Integer,String是数据类型。primary_key,nullable,unique等是列的约束和属性。__repr__: 定义了对象的字符串表示形式,方便调试。
第二步:创建引擎和会话
python
# 创建数据库引擎 (这里使用SQLite)
engine = create_engine('sqlite:///library_orm.db', echo=True) # echo=True 会打印执行的SQL语句
# 创建所有表 (如果表不存在)
Base.metadata.create_all(engine)
# 创建会话工厂
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
# 创建一个会话实例 (相当于之前的cursor)
db_session = SessionLocal()
代码解析:
create_engine(): 创建一个数据库引擎,它负责与数据库进行通信。URLsqlite:///library_orm.db指定了数据库的类型和位置。echo=True: 一个非常有用的调试选项,它会将所有执行的SQL语句打印到控制台。Base.metadata.create_all(engine): 这行代码会扫描所有继承自Base的模型类,并在数据库中创建对应的表(如果表还不存在)。sessionmaker(): 创建一个会话工厂,用于生成与数据库交互的会话(Session)对象。
第三步:使用ORM进行CRUD操作
python
try:
# --- CREATE (创建) ---
# 创建一个Book对象
new_book = Book(
title="Brave New World",
author="Aldous Huxley",
isbn="978-0-06-085052-4",
published_year=1932,
genre="Science Fiction"
)
# 将对象添加到会话中
db_session.add(new_book)
# 提交事务
db_session.commit()
print(f"Book '{new_book.title}' added via ORM.")
# --- READ (读取) ---
# 查询所有书籍
all_books_orm = db_session.query(Book).all()
print("\nAll Books (via ORM):")
for book in all_books_orm:
print(book)
# 查询特定作者的书籍
orwell_books_orm = db_session.query(Book).filter(Book.author == "George Orwell").all()
print("\nBooks by George Orwell (via ORM):")
for book in orwell_books_orm:
print(f"- {book.title} ({book.published_year})")
# 查询单个对象
specific_book = db_session.query(Book).filter(Book.title == "1984").first()
if specific_book:
print(f"\nFound book: {specific_book}")
# --- UPDATE (更新) ---
book_to_update = db_session.query(Book).filter(Book.title == "1984").first()
if book_to_update:
book_to_update.genre = "Classic Dystopian Fiction"
db_session.commit() # 提交更改
print(f"\nBook '{book_to_update.title}' genre updated via ORM.")
# --- DELETE (删除) ---
book_to_delete = db_session.query(Book).filter(Book.title == "To Kill a Mockingbird").first()
if book_to_delete:
db_session.delete(book_to_delete)
db_session.commit() # 提交删除
print(f"Book '{book_to_delete.title}' deleted via ORM.")
else:
print("\nBook 'To Kill a Mockingbird' not found for deletion.")
except Exception as e:
# 如果发生错误,回滚事务
db_session.rollback()
print(f"An error occurred: {e}")
finally:
# 关闭会话
db_session.close()
代码解析:
db_session.add(obj): 将一个Python对象(Book实例)标记为"待新增"。db_session.query(Model): 开始构建一个查询。.filter(),.all(),.first(),.one_or_none()等方法用于构建和执行查询。db_session.commit(): 提交会话中的所有更改到数据库。db_session.rollback(): 在发生错误时,撤销所有未提交的更改,保证数据一致性。这是使用ORM进行事务管理的重要环节。- 核心思想: ORM将复杂的SQL操作封装成了直观的Python对象操作,极大地提高了开发效率和代码的可读性。
第四部分:连接MySQL和PostgreSQL
sqlite3模块只适用于SQLite。对于更大型的项目,我们通常会使用MySQL或PostgreSQL。这时,你需要安装相应的驱动程序。
- MySQL :
pip install PyMySQL或pip install mysqlclient - PostgreSQL :
pip install psycopg2-binary
然后,只需更改create_engine中的URL即可。
python
# 连接MySQL
mysql_engine = create_engine('mysql+pymysql://username:password@host:port/database_name')
# 连接PostgreSQL
pg_engine = create_engine('postgresql+psycopg2://username:password@host:port/database_name')
其余的ORM操作(模型定义、查询、增删改)完全相同。
第五部分:最佳实践与注意事项
- 使用连接池 :
SQLAlchemy的引擎默认包含一个连接池,可以有效管理数据库连接,避免频繁创建和销毁连接带来的性能损耗。 - 参数化查询: 无论是使用原生SQL还是ORM,都必须使用参数化查询来防止SQL注入攻击。
- 事务管理 : 对于涉及多个操作的业务逻辑,务必使用事务(
commit/rollback)来保证数据的原子性。 - 索引 : 为经常用于查询条件的列(如
WHERE,ORDER BY,JOIN子句中的列)创建索引,可以显著提升查询速度。 - 选择合适的工具 : 对于简单、快速的脚本,
sqlite3原生模块足够了。对于复杂的、需要团队协作的Web应用,ORM(如SQLAlchemy)是更好的选择。