使用 Python 内置的 SQLite 数据库完成实验。无需安装任何软件,只要电脑有 Python 就能直接运行。
请将每个脚本的运行结果截图保存,整理到实验报告模板中提交。
import sqlite3 即可使用,不需要安装 MySQL、不需要启动任何服务、不需要输入密码。| 对比项 | MySQL(PyMySQL) | SQLite(sqlite3) |
|---|---|---|
| 导入模块 | import pymysql | import sqlite3(内置) |
| 连接方式 | pymysql.connect(host, user, password, database) | sqlite3.connect('文件名.db') |
| 参数占位符 | %s | ? |
| 是否需要安装 | 需要安装 MySQL 服务 + pip install pymysql | Python 自带,什么都不用装 |
| 数据存储 | MySQL 服务器中 | 一个本地 .db 文件 |
新建文件 lab4_create.py,将下面的完整代码复制进去运行。运行后会在同目录下自动生成一个 student.db 数据库文件。
# ======================================================= # 脚本一:创建数据库、数据表,并插入学生记录 # ======================================================= # sqlite3 是 Python 自带的模块,无需安装,直接导入即可 import sqlite3 # ---------------------------------------------------------- # 第1步:连接数据库 # ---------------------------------------------------------- # sqlite3.connect() 会连接到指定的数据库文件 # 如果文件不存在,会自动创建一个新的数据库文件 # 这里会在当前目录下生成 student.db 文件 # (对比 MySQL:pymysql.connect(host=..., user=..., password=..., database=...)) conn = sqlite3.connect('student.db') # ---------------------------------------------------------- # 第2步:获取游标对象 # ---------------------------------------------------------- # 游标(cursor)是用来执行 SQL 语句的工具 # 你可以把它想象成数据库上的一根"手指",指哪查哪 cursor = conn.cursor() print("✅ 已连接数据库 student.db") # ---------------------------------------------------------- # 第3步:创建学生信息表 tb_students # ---------------------------------------------------------- # CREATE TABLE IF NOT EXISTS:如果表不存在就创建,已存在就跳过 # 字段说明: # id - 整数,主键(每行的唯一标识),自增长 # name - 文本,学生姓名,不允许为空 # age - 整数,学生年龄,默认值 18 # major - 文本,所学专业,默认值 '未分配' # enroll_date - 文本,入学日期(SQLite 没有 DATE 类型,用 TEXT 存储日期字符串) create_sql = """ CREATE TABLE IF NOT EXISTS tb_students ( id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT NOT NULL, age INTEGER DEFAULT 18, major TEXT DEFAULT '未分配', enroll_date TEXT ) """ cursor.execute(create_sql) print("✅ 数据表 tb_students 已创建") # ---------------------------------------------------------- # 第4步:插入 5 条学生记录 # ---------------------------------------------------------- # 使用参数化查询:用 ? 作为占位符(MySQL 中用 %s) # 这样可以防止 SQL 注入攻击,也更安全 insert_sql = "INSERT INTO tb_students (name, age, major, enroll_date) VALUES (?, ?, ?, ?)" # 准备数据:一个列表,每个元素是一个元组,对应一行记录 students = [ ('张三', 20, '计算机科学', '2024-09-01'), ('李四', 19, '软件工程', '2024-09-01'), ('王五', 21, '计算机科学', '2023-09-01'), ('赵六', 20, '数据科学', '2024-09-01'), ('孙七', 22, '人工智能', '2023-09-01'), ] # executemany() 批量插入:一次性将列表中的所有数据插入表中 # 比用 for 循环逐条 execute() 效率更高 cursor.executemany(insert_sql, students) # ---------------------------------------------------------- # 第5步:提交事务 # ---------------------------------------------------------- # 增删改操作必须调用 commit(),否则数据不会真正保存到文件中 # 只有查询(SELECT)不需要 commit() conn.commit() print(f"✅ 成功插入 {len(students)} 条学生记录") # ---------------------------------------------------------- # 第6步:查询并展示所有数据,验证插入是否成功 # ---------------------------------------------------------- # execute() 执行 SELECT 查询后,用 fetchall() 获取全部结果 # 返回的结果是一个列表,每个元素是一个元组(代表一行数据) cursor.execute("SELECT * FROM tb_students") results = cursor.fetchall() print("\n📋 当前 tb_students 表中的所有记录:") print("-" * 60) print(f"{'学号':<6}{'姓名':<8}{'年龄':<6}{'专业':<12}{'入学日期'}") print("-" * 60) for row in results: # row 是元组,row[0]=id, row[1]=name, row[2]=age, row[3]=major, row[4]=enroll_date print(f"{row[0]:<6}{row[1]:<8}{row[2]:<6}{row[3]:<12}{row[4]}") print(f"\n共 {len(results)} 条记录") # ---------------------------------------------------------- # 第7步:关闭游标和连接,释放资源 # ---------------------------------------------------------- # 用完数据库后一定要关闭,就像用完水龙头要关上一样 cursor.close() conn.close() print("🔒 数据库连接已关闭")
lab4_create.py 同目录下看到一个新文件 student.db,这就是你的数据库。SQLite 的数据库就是一个普通文件,可以拷贝、删除、发送给别人。
新建文件 lab4_query.py(放在和脚本一相同的目录下),复制以下代码。
# ======================================================= # 脚本二:多种查询方式演示 # ======================================================= import sqlite3 # 连接到已有的数据库文件(脚本一创建的 student.db) conn = sqlite3.connect('student.db') cursor = conn.cursor() # ---------------------------------------------------------- # 查询1:条件查询 —— WHERE 过滤年龄 >= 20 的学生 # ---------------------------------------------------------- # WHERE 子句用来设置查询条件,只返回满足条件的行 # 注意 SQLite 的占位符是 ?(不是 MySQL 的 %s) print("🔍 查询1:年龄 >= 20 的学生") print("-" * 45) cursor.execute("SELECT name, age, major FROM tb_students WHERE age >= ?", (20,)) for row in cursor.fetchall(): print(f" 姓名: {row[0]}, 年龄: {row[1]}, 专业: {row[2]}") # ---------------------------------------------------------- # 查询2:模糊查询 —— LIKE 查找专业名中包含"科"字的学生 # ---------------------------------------------------------- # LIKE 用于模式匹配,% 代表任意多个字符 # '%科%' 的意思是:只要"科"出现在任意位置就匹配 print(f'\n🔍 查询2:专业包含"科"字的学生') print("-" * 45) cursor.execute("SELECT name, major FROM tb_students WHERE major LIKE ?", ('%科%',)) for row in cursor.fetchall(): print(f" 姓名: {row[0]}, 专业: {row[1]}") # ---------------------------------------------------------- # 查询3:统计函数 —— COUNT / AVG / MAX / MIN # ---------------------------------------------------------- # 统计函数对整列数据进行计算,返回单个结果 # COUNT(*) 统计总行数,AVG() 求平均值,MAX() 最大值,MIN() 最小值 print(f"\n🔍 查询3:统计信息") print("-" * 45) cursor.execute("SELECT COUNT(*), AVG(age), MAX(age), MIN(age) FROM tb_students") stats = cursor.fetchone() # fetchone() 只取一条结果(因为统计函数只返回一行) print(f" 总人数: {stats[0]}") print(f" 平均年龄: {stats[1]:.1f}") # :.1f 保留一位小数 print(f" 最大年龄: {stats[2]}") print(f" 最小年龄: {stats[3]}") # ---------------------------------------------------------- # 查询4:排序 + 限制条数 —— ORDER BY ... LIMIT # ---------------------------------------------------------- # ORDER BY age DESC:按年龄降序排列(从大到小) # LIMIT 3:只取前 3 条结果 print(f"\n🔍 查询4:按年龄降序排列(前3名)") print("-" * 45) cursor.execute("SELECT name, age FROM tb_students ORDER BY age DESC LIMIT 3") for i, row in enumerate(cursor.fetchall(), 1): print(f" 第{i}名: {row[0]}, {row[1]}岁") # ---------------------------------------------------------- # 查询5:分组统计 —— GROUP BY 按专业分组统计人数 # ---------------------------------------------------------- # GROUP BY major:将相同专业的行分为一组 # 再对每组使用 COUNT(*) 统计该组有多少人 print(f"\n🔍 查询5:各专业学生人数") print("-" * 45) cursor.execute("SELECT major, COUNT(*) as cnt FROM tb_students GROUP BY major") for row in cursor.fetchall(): print(f" {row[0]}: {row[1]} 人") # ---------------------------------------------------------- # 关闭连接 # ---------------------------------------------------------- # 查询操作不修改数据,所以不需要 commit(),直接关闭即可 cursor.close() conn.close() print("\n🔒 数据库连接已关闭")
lab4_create.py 的完整输出(包括连接成功、建表、插入记录数、5条学生数据表格)lab4_query.py 的完整输出(包括5个查询的结果)
try → commit / except → rollback / finally → close。这个模板在 SQLite 和 MySQL 中完全通用,是实际开发中必须掌握的编码规范。
新建文件 lab4_safe.py(同目录),复制以下代码运行。
# ======================================================= # 脚本三:带异常处理的修改与删除操作 # ======================================================= # 本脚本演示数据库操作的"黄金模板": # try → 执行操作,成功就 commit(提交) # except → 出错就 rollback(回滚,撤销所有修改) # finally → 无论成功失败,都 close(关闭连接) # 这个结构在 SQLite 和 MySQL 中完全一样! import sqlite3 # ---------------------------------------------------------- # 建立连接 # ---------------------------------------------------------- conn = sqlite3.connect('student.db') try: # 获取游标 cursor = conn.cursor() # ---------------------------------------------------------- # 操作前:查看当前所有数据(方便和操作后对比) # ---------------------------------------------------------- print("📋 操作前的数据:") print("-" * 55) cursor.execute("SELECT * FROM tb_students") for row in cursor.fetchall(): print(f" {row[0]} | {row[1]:<4} | {row[2]}岁 | {row[3]}") # ---------------------------------------------------------- # 操作1:UPDATE —— 将"李四"的专业改为"人工智能" # ---------------------------------------------------------- # UPDATE 语法:UPDATE 表名 SET 列名 = 新值 WHERE 条件 # 一定要带 WHERE!否则会把所有行都改了 sql_update1 = "UPDATE tb_students SET major = ? WHERE name = ?" cursor.execute(sql_update1, ('人工智能', '李四')) # cursor.rowcount 返回本次操作影响了多少行 print(f"\n✏️ 操作1 UPDATE:修改了 {cursor.rowcount} 条记录(李四的专业 → 人工智能)") # ---------------------------------------------------------- # 操作2:UPDATE —— 将所有"计算机科学"专业学生的年龄 +1 # ---------------------------------------------------------- # SET age = age + 1:在原来的年龄基础上加 1 # 这里 WHERE 条件匹配了多行,所以会修改多条记录 sql_update2 = "UPDATE tb_students SET age = age + 1 WHERE major = ?" cursor.execute(sql_update2, ('计算机科学',)) print(f"✏️ 操作2 UPDATE:{cursor.rowcount} 名计算机科学学生年龄 +1") # ---------------------------------------------------------- # 操作3:DELETE —— 删除年龄小于 20 的学生 # ---------------------------------------------------------- # DELETE FROM 语法:DELETE FROM 表名 WHERE 条件 # 同样一定要带 WHERE!否则会删除所有数据 sql_delete = "DELETE FROM tb_students WHERE age < ?" cursor.execute(sql_delete, (20,)) print(f"🗑️ 操作3 DELETE:删除了 {cursor.rowcount} 条记录(年龄 < 20 的学生)") # ---------------------------------------------------------- # 操作后:再次查询,对比数据变化 # ---------------------------------------------------------- print(f"\n📋 操作后的数据:") print("-" * 55) cursor.execute("SELECT * FROM tb_students") final = cursor.fetchall() for row in final: print(f" {row[0]} | {row[1]:<4} | {row[2]}岁 | {row[3]}") print(f"共 {len(final)} 条记录") # ---------------------------------------------------------- # 全部操作成功,提交事务 # ---------------------------------------------------------- # commit() 让所有修改永久生效,写入到 .db 文件中 conn.commit() print("\n✅ 所有操作已成功提交!") except Exception as e: # ---------------------------------------------------------- # 任何一步出错,撤销本次所有修改 # ---------------------------------------------------------- # rollback() 回滚事务:把数据恢复到 try 开始前的状态 # 这样就不会出现"改了一半"的不一致数据 conn.rollback() print(f"\n❌ 操作失败,已全部回滚: {e}") finally: # ---------------------------------------------------------- # 无论成功或失败,最终都要关闭连接 # ---------------------------------------------------------- # finally 块中的代码一定会执行,确保资源不泄露 cursor.close() conn.close() print("🔒 数据库连接已关闭")
rollback() 就是让银行系统把 A 的钱退回去。commit() 则是确认"扣款和到账都成功了,这笔交易正式生效"。finally 保证不管转账成功还是失败,你最后都会走出银行(关闭连接)。
lab4_safe.py 的完整输出(包括操作前数据、3个操作的影响行数、操作后数据、提交成功和关闭信息)
完成全部实验后,将以下 3 张截图按顺序粘贴到学校的 Word 实验报告模板中提交。
student.db 文件,然后从脚本一重新运行即可。
.py 文件必须放在同一个文件夹下,因为它们共用同一个 student.db 数据库文件。