上一篇
一个简单的数据库代码怎么写
- 数据库
- 2025-08-23
- 5
Python结合SQLite,先导入sqlite3库,创建连接与游标,执行建表语句如
CREATE TABLE tb(id INT PRIMARY KEY, name TEXT)
,再增删改查
理解需求与选择工具
要创建一个“简单”的数据库系统,首先需明确目标:存储结构化数据(如用户信息、商品清单)、支持增删改查操作(CRUD),对于初学者而言,推荐使用轻量级关系型数据库管理系统(RDBMS),SQLite(无需安装服务器,文件即数据库)或 MySQL/PostgreSQL(适合进阶练习),这里以 Python + SQLite 组合为例,因其跨平台且语法直观。
关键技术栈对比表:
组件 | 推荐方案 | 优势 |
---|---|---|
编程语言 | Python | 语法简洁,生态丰富(如Pandas) |
数据库引擎 | SQLite | 零配置,嵌入到应用程序中 |
ORM框架 | 原生SQL / peewee库 | 直接控制SQL或简化对象映射 |
环境准备与基础架构搭建
安装依赖库
若使用Python开发,需确保已安装sqlite3
模块(Python标准库自带),可选装第三方库提升效率:
pip install pandas # 用于数据分析辅助验证结果 pip install prettytable # 美化终端输出表格展示
设计数据模型
假设我们要管理一本书籍收藏夹,核心字段包括:ID(主键)、书名、作者、出版年份、评分,对应的SQL建表语句如下:
CREATE TABLE IF NOT EXISTS books ( id INTEGER PRIMARY KEY AUTOINCREMENT,TEXT NOT NULL, author TEXT, year_published INTEGER, rating REAL CHECK(rating >= 0 AND rating <= 10) );
- 约束说明:
NOT NULL
确保必填项;CHECK
限制评分范围为[0,10]。
核心功能实现代码详解
以下是完整的Python脚本示例,包含连接数据库、执行CRUD操作及异常处理:
import sqlite3 from contextlib import closing import sys class BookDatabase: def __init__(self, db_name='library.db'): self.conn = None self.db_path = db_name self._initialize_schema() def _initialize_schema(self): """首次运行时自动创建表结构""" with closing(sqlite3.connect(self.db_path)) as conn: cursor = conn.cursor() cursor.execute(''' CREATE TABLE IF NOT EXISTS books ( id INTEGER PRIMARY KEY AUTOINCREMENT, title TEXT NOT NULL, author TEXT, year_published INTEGER, rating REAL CHECK(rating >= 0 AND rating <= 10) ); ''') conn.commit() def add_book(self, title, author, year, rating): """插入新书记录""" try: with closing(sqlite3.connect(self.db_path)) as conn: cursor = conn.cursor() cursor.execute( "INSERT INTO books (title, author, year_published, rating) VALUES (?, ?, ?, ?)", (title, author, year, float(rating)) ) conn.commit() return cursor.lastrowid # 返回自增ID except ValueError as e: print(f"输入错误: {str(e)}", file=sys.stderr) return None except sqlite3.IntegrityError as e: print(f"违反唯一性约束或其他完整性规则: {str(e)}", file=sys.stderr) return None def delete_book(self, book_id): """根据ID删除指定书籍""" affected_rows = 0 with closing(sqlite3.connect(self.db_path)) as conn: cursor = conn.cursor() affected_rows = cursor.execute( "DELETE FROM books WHERE id = ?", (book_id,) ).rowcount conn.commit() return affected_rows > 0 def update_book(self, book_id, new_title=None, new_author=None, new_year=None, new_rating=None): """动态更新部分字段""" params = [] set_clauses = [] if new_title is not None: set_clauses.append("title = ?") params.append(new_title) if new_author is not None: set_clauses.append("author = ?") params.append(new_author) if new_year is not None: set_clauses.append("year_published = ?") params.append(new_year) if new_rating is not None: set_clauses.append("rating = ?") params.append(float(new_rating)) if not set_clauses: raise ValueError("至少提供一个可更新的字段") sql = f"UPDATE books SET {', '.join(set_clauses)} WHERE id = ?" params.append(book_id) with closing(sqlite3.connect(self.db_path)) as conn: cursor = conn.cursor() cursor.execute(sql, params) conn.commit() return cursor.rowcount == 1 def list_all_books(self): """查询所有书籍并以易读格式返回""" result = [] with closing(sqlite3.connect(self.db_path)) as conn: conn.row_factory = sqlite3.Row # 允许按列名访问行数据 cursor = conn.cursor() for row in cursor.execute("SELECT FROM books ORDER BY id"): result.append({ 'ID': row['id'], '书名': row['title'], '作者': row['author'], '出版年份': row['year_published'], '评分': round(row['rating'], 1) }) return result # 测试用例演示 if __name__ == "__main__": db = BookDatabase() # 添加示例数据 db.add_book("三体", "刘慈欣", 2006, 9.5) db.add_book("百年孤独", "加西亚·马尔克斯", 1967, 9.8) # 更新第一条记录的评分 db.update_book(1, new_rating=9.7) # 删除第二条记录 db.delete_book(2) # 打印当前所有书籍 books = db.list_all_books() from prettytable importPrettyTable tbl = PrettyTable(["ID", "书名", "作者", "出版年份", "评分"]) for b in books: tbl.add_row([b['ID'], b['书名'], b['作者'], b['出版年份'], b['评分']]) print(tbl)
代码逐行解析:
- 类初始化:
BookDatabase
类封装了所有数据库交互逻辑,构造函数自动调用_initialize_schema()
方法确保表存在。 - 事务管理:使用
with closing()
上下文管理器自动提交/回滚事务,避免手动处理连接关闭问题。 - 参数化查询:所有SQL语句均使用问号占位符(),防止SQL注入攻击,例如插入操作中的
VALUES (?, ?, ?, ?)
。 - 动态更新逻辑:
update_book()
方法允许只修改部分字段,通过条件判断构建SET子句。 - 错误处理:捕获类型转换异常(如非数字的评分)、主键冲突等常见错误并给出友好提示。
- 结果格式化:利用
sqlite3.Row
工厂将查询结果转为字典形式,配合prettytable
库生成美观的控制台表格。
扩展建议与最佳实践
- 索引优化:频繁查询的列应建立索引以提高性能,例如为
title
添加全文搜索索引:CREATE INDEX idx_title ON books(title);
- 备份机制:定期导出SQL脚本或复制物理文件进行备份,SQLite可通过命令行工具实现:
sqlite3 library.db .dump > backup_$(date +%Y%m%d).sql
- 迁移工具:生产环境中推荐使用Alembic等版本控制工具管理数据库结构变更。
- 安全加固:限制用户权限(如只读账户)、启用WAL模式提升并发写入能力。
FAQs常见问题解答
Q1: 如果运行代码时出现“OperationalError: unable to open database file”,该怎么办?
A: 此错误通常由以下原因导致:①文件路径无写入权限(检查目录是否存在且用户有读写权);②跨设备链接符号链接失效(确保数据库文件与应用程序在同一磁盘分区),解决方案包括:切换到绝对路径指定数据库位置,或手动创建空文件后赋予适当权限,例如在Linux下执行:touch /path/to/library.db && chmod 664 /path/to/library.db
。
Q2: 如何将现有CSV文件中的数据批量导入到这个数据库中?
A: 可以使用Python的csv
模块结合事务批量插入,示例代码如下:
import csv with open('books.csv', 'r', encoding='utf-8') as f: reader = csv.DictReader(f) with closing(sqlite3.connect(self.db_path)) as conn: cursor = conn.cursor() for row in reader: cursor.execute(''' INSERT INTO books (title, author, year_published, rating) VALUES (?, ?, ?, ?) ''', (row['title'], row['author'], int(row['year']), float(row['rating']))) conn.commit()
注意需确保CSV列名与数据库字段完全匹配,并对数值类型做显式转换