前言:本篇为 MySQL 系列第二篇,承接上一篇 pymysql 连接 MySQL 基础,系统梳理 MySQL 常用 SQL 语法、语句分类,以及 pymysql 库核心 API。附带完整可运行 Python 示例,演示建库、建表、主外键、增删改查、事务回滚整套流程,适合 Python 操作 MySQL 入门学习。
一、完整示例代码
沿用 pymysql,一次性演示数据库连接、建库、建表、主键外键、多表关联查询、增删改查、事务回滚、删库全流程。
import pymysql
database_name = 'testmysql'
delete_database = True # True执行删库,False保留数据库
# delete_database = False
# 建立数据库连接
connection = pymysql.connect(
host='localhost',
port=3306,
user='test',
password='mysql',
charset='utf8mb4',
# database=database_name, # 先不指定库,后面手动use切换
)
# SQL语句定义
create_database_sql = f'CREATE DATABASE IF NOT EXISTS {database_name};'
show_sql = 'SHOW databases;'
goto_database = f'USE {database_name};'
# 创建班级表
create_table_Classes_sql = '''
CREATE TABLE IF NOT EXISTS 班级 (
班号 INT AUTO_INCREMENT PRIMARY KEY,
班名 VARCHAR(100) NOT NULL,
班导 VARCHAR(100)
);
'''
# 创建学生表,设置外键,级联删除、级联更新
create_table_Students_sql = '''
CREATE TABLE IF NOT EXISTS 学生 (
学号 INT AUTO_INCREMENT PRIMARY KEY,
姓名 VARCHAR(100) NOT NULL,
性别 ENUM('男', '女', '其他','直升机') NOT NULL,
民族 VARCHAR(50),
班级 INT,
FOREIGN KEY (班级) REFERENCES 班级(班号) ON DELETE CASCADE ON UPDATE CASCADE
);
'''
delete_database_sql = f'DROP DATABASE IF EXISTS {database_name};'
try:
with connection.cursor() as cursor:
cursor.execute(show_sql)
all_database_name = cursor.fetchall()
if not (database_name,) in all_database_name:
# 1. 创建数据库
cursor.execute(create_database_sql)
cursor.execute(show_sql)
all_database_name = cursor.fetchall()
if (database_name,) in all_database_name:
print('数据库创建完成')
cursor.execute(goto_database)
# 2. 创建数据表
cursor.execute(create_table_Classes_sql)
cursor.execute(create_table_Students_sql)
# 3. 插入数据
insert_Class_sql = '''
INSERT INTO 班级 (班名, 班导) VALUES (%s, %s),(%s, %s),(%s, %s)
'''
data_Class = ['日升班', '道光', '伏流班', '汪洋', '腾渊班', '菲杨']
cursor.execute(insert_Class_sql, data_Class)
insert_Students_sql = '''
INSERT INTO 学生 (姓名, 性别,民族,班级) VALUES (%s, %s, %s, %s)
'''
name = ['赵匡胤', '钱镠', '孙悟空', '武曌', '曹雪芹', '杰瑞', '张三', '约翰·纳什', '武直-10']
sex0 = ['男', '男', '男', '女', '男', '其他', '男', '男', '直升机']
nati = ['汉', '汉', '汉', '汉', '满', '米奇', '汉', '维京', '中华民族']
clas = [2, 3, 3, 2, 1, 1, 1, 2, 3]
data = [[name[i], sex0[i], nati[i], clas[i]] for i in range(len(name))]
cursor.executemany(insert_Students_sql, data)
connection.commit()
# 4. 删除数据
delete_sql = 'DELETE FROM 学生 WHERE 姓名=%s;'
cursor.execute(delete_sql, '杰瑞')
connection.commit()
# 5. 更新数据
change_sql = 'UPDATE 学生 SET 性别 = %s,民族 = %s WHERE 姓名 = %s;'
cursor.executemany(change_sql, (('其他', None, '孙悟空'),))
connection.commit()
# 6. 查询数据
select_classes_sql = 'SELECT * FROM 班级'
cursor.execute(select_classes_sql)
classes = cursor.fetchall()
print('班级有:')
for class_info in classes:
print(class_info)
# 子查询跨表
select_students_sql = '''
SELECT * FROM 学生
WHERE 班级 in (SELECT 班号 FROM 班级 WHERE 班名 = %s);
'''
cursor.execute(select_students_sql, '腾渊班')
students = cursor.fetchall()
print('腾渊班的学生有:')
for student_info in students:
print(student_info)
# JOIN联表查询
select_students_sql = '''
SELECT 学生.*
FROM 学生 JOIN 班级 ON 学生.班级 = 班级.班号
WHERE 班级.班名 = %s;
'''
cursor.execute(select_students_sql, '伏流班')
students = cursor.fetchall()
print('伏流班的学生有:')
for student_info in students:
print(student_info)
# 7. 删除数据库
if delete_database:
cursor.execute(delete_database_sql)
cursor.execute(show_sql)
all_database_name = cursor.fetchall()
if not (database_name,) in all_database_name:
print('数据库删除完成')
else:
print('未删除数据库')
else:
print(f"数据库 {database_name} 已存在,为防止误删,程序终止")
connection.commit()
except pymysql.MySQLError as e:
print(f"Error: {e}")
connection.rollback() # 异常回滚事务
finally:
connection.close()
print('数据库链接已关闭')
二、常用 SQL 语句与基础概念
SQL 大小写不敏感;数据库、表、字段名是否区分大小写,由 MySQL 服务配置决定。 MySQL 语句末尾必须使用分号
;,语句中空格、换行会被忽略。
2.1 SQL 语句四大分类
表格
| 分类 | 全称 | 作用 |
|---|---|---|
| DDL | 数据定义语言 | 创建、修改、删除数据库对象(库、表) |
| DML | 数据操作语言 | 对表里的数据做增删改查 |
| DCL | 数据控制语言 | 用户权限管理 |
| TCL | 事务控制语言 | 事务提交、回滚管理 |
2.2 SQL 注释写法
-- 单行注释(--后面必须加空格)
# 单行注释,不需要空格
/*
多行注释
可以跨行写内容
*/
2.3 DDL 数据定义语言
DDL 语句执行时会隐式提交事务 ,一旦执行无法回滚,操作务必谨慎。 表名、字段名如果和 mysql 关键字冲突,使用反引号 ````` 包裹。
数据库相关操作
-- 创建数据库
CREATE DATABASE [IF NOT EXISTS] `数据库名` [CHARACTER SET 'utf8mb4'];
-- 删除数据库
DROP DATABASE [IF EXISTS] `数据库名`;
-- 查看所有数据库
SHOW DATABASES;
-- 切换使用的数据库
USE `数据库名`;
-- 查看当前所在数据库
SELECT DATABASE();
数据表相关操作
-- 查询当前库所有表
SHOW TABLES;
-- 查看表结构
DESC `表名`;
-- 查看建表SQL
SHOW CREATE TABLE `表名`;
建表基础语法
CREATE TABLE `表名` (
字段名 类型 [约束] [COMMENT '注释'],
字段名 类型 [约束] [COMMENT '注释']
);
MySQL 常用数据类型
- 整型:
BIGINT、INT、MEDIUMINT、SMALLINT、TINYINT,占用字节依次 8/4/3/2/1 - 浮点数:
FLOAT单精度、DOUBLE双精度 - 定点数:
DECIMAL(M,D),例如DECIMAL(3,2)总 3 位,保留 2 位小数,适合金额 - 时间日期:
DATE(YYYY-MM-DD)、TIME(HH:MM)、DATETIME、TIMESTAMP - 字符串
CHAR(n)固定长度,查询速度快,最大 255 字符,不足补空格VARCHAR(n)可变长度,仅占用实际字符空间TEXT长文本,不用指定最大长度
- 枚举集合
ENUM单选,只能取预先定义好的其中一个值SET多选,可以选取预定义多个值
表约束
表格
| 约束 | 说明 |
|---|---|
| PRIMARY KEY | 主键,唯一标识一行数据 |
| UNIQUE | 唯一约束,字段值不能重复 |
| NOT NULL | 非空约束,字段不允许为 NULL |
| DEFAULT | 默认值,插入不填时自动填充默认值 |
| FOREIGN KEY | 外键约束,关联另一张表主键 |
| CHECK | 检查约束,限制字段取值规则 |
修改表结构
-- 添加列
ALTER TABLE 表名 ADD 字段名 字段类型 [约束];
-- 删除列
ALTER TABLE 表名 DROP COLUMN 字段名;
-- 修改字段类型
ALTER TABLE 表名 MODIFY COLUMN 字段名 新类型 ;
-- 修改表名
ALTER TABLE 表名 RENAME TO 新表名;
2.4 DML 数据操作语言(增删改查)
-- 新增数据
INSERT INTO 表名 [(字段1, 字段2)] VALUES (值1,值2),(值1,值2);
-- 删除数据,务必加WHERE条件!
DELETE FROM 表名 WHERE 条件;
-- 更新数据,不加WHERE会修改全表!
UPDATE 表名 SET 字段1=值,字段2=值 WHERE 条件;
-- 查询数据
SELECT 字段1,字段2 FROM 表名 WHERE 条件;
-- * 代表查询全部字段
2.5 DCL 权限控制语句
日常开发使用较少,用于管理数据库账号权限
-- 授予权限
GRANT 权限1, 权限2 ON 表名 TO 用户名 [WITH GRANT OPTION];
-- 撤销权限
REVOKE 权限1, 权限2 ON 表名 FROM 用户名;
2.6 TCL 事务控制语言
事务:一组 SQL 操作作为一个原子单元,全部执行成功,或者全部回滚,保证数据一致性。 MySQL 默认每条 DML 语句自动作为独立事务提交。
-- 开启事务
START TRANSACTION;
BEGIN TRANSACTION;
-- 提交事务,持久化修改
COMMIT;
-- 回滚,撤销本次事务内所有操作
ROLLBACK;
-- 设置保存点
SAVEPOINT 保存点名称;
三、pymysql 核心常用函数
1. 数据库连接
connection = pymysql.connect(
host='localhost',
port=3306,
user='root',
password='xxx',
database='testdb',
charset='utf8mb4'
)
# 关闭连接
connection.close()
2. 事务操作
connection.commit() # 提交事务
connection.rollback() # 事务回滚
3. 游标 cursor(执行 SQL、读取结果)
# 创建游标
cursor = connection.cursor()
# with语法自动关闭游标,推荐写法
with connection.cursor() as cursor:
pass
cursor.close()
4. SQL 执行 & 获取结果集
表格
| 方法 | 功能 |
|---|---|
cursor.execute(sql, args) |
执行单条 SQL,返回受影响行数 |
cursor.executemany(sql, args_list) |
批量执行多条 SQL,适合批量插入 |
cursor.fetchone() |
获取查询结果第一条数据 |
cursor.fetchmany(size) |
获取指定 size 条结果 |
cursor.fetchall() |
获取全部查询结果 |
cursor.rowcount |
本次 execute 影响的数据行数 |
游标可以理解为结果集的指针,fetch 读取数据后,指针向后移动,重复 fetch 不会重复读到前面的数据。
四、小结
- DDL 操作库表结构,隐式提交,不能回滚;DML 操作表内数据,需要手动 commit/rollback 管理事务。
- 外键可以做表关联,支持级联更新 / 删除,开发中根据业务取舍。
- pymysql 中推荐
with管理游标,异常捕获配合rollback防止脏数据。 - 查询不需要 commit;新增、修改、删除操作,必须 commit 才会真正写入数据库。