1. MySQL数据库创建基础操作
1.1 数据库创建语法详解
在MySQL中创建数据库是最基础的操作之一,使用CREATE DATABASE语句可以快速创建一个新的数据库。完整的语法结构如下:
sql复制CREATE DATABASE [IF NOT EXISTS] database_name
[CHARACTER SET charset_name]
[COLLATE collation_name];
其中,IF NOT EXISTS是可选的,用于避免在数据库已存在时报错。CHARACTER SET用于指定数据库的字符集,常见的字符集包括utf8mb4(支持完整的Unicode字符)和gbk(中文编码)。COLLATE则用于指定排序规则,例如utf8mb4_general_ci(不区分大小写)或utf8mb4_bin(二进制比较,区分大小写)。
实际工作中,我建议始终使用utf8mb4字符集,因为它能完美支持emoji表情和所有Unicode字符。一个完整的创建示例如下:
sql复制CREATE DATABASE IF NOT EXISTS my_shop
CHARACTER SET utf8mb4
COLLATE utf8mb4_general_ci;
1.2 数据库选择与状态检查
创建数据库后,需要使用USE语句选择当前操作的数据库:
sql复制USE database_name;
要查看数据库的创建信息,可以使用SHOW CREATE DATABASE语句:
sql复制SHOW CREATE DATABASE my_shop;
这条命令会返回数据库的完整创建语句,包括字符集和排序规则等详细信息。对于数据库管理,我习惯在创建后立即执行这个命令,确认所有参数设置正确。
2. 数据表设计与创建实战
2.1 数据表创建基础语法
数据表是数据库中存储数据的核心结构。创建表的基本语法如下:
sql复制CREATE TABLE [IF NOT EXISTS] table_name (
column1 datatype constraints,
column2 datatype constraints,
...
[table_constraints]
) [ENGINE=storage_engine];
每个列定义包含列名、数据类型和可选的约束条件。表级约束则定义在列定义之后。ENGINE用于指定存储引擎,常用的有InnoDB(支持事务)和MyISAM(查询性能高但不支持事务)。
2.2 常用数据类型选择
MySQL支持多种数据类型,合理选择数据类型对性能和存储空间至关重要:
- 整数类型:TINYINT(1字节)、SMALLINT(2字节)、INT(4字节)、BIGINT(8字节)
- 小数类型:FLOAT(单精度)、DOUBLE(双精度)、DECIMAL(精确小数)
- 字符串类型:CHAR(定长)、VARCHAR(变长)、TEXT(长文本)
- 日期时间:DATE(日期)、TIME(时间)、DATETIME(日期时间)、TIMESTAMP(时间戳)
在实际项目中,我通常会遵循以下原则:
- 能用整数就不用字符串
- 根据数据范围选择最小够用的整数类型
- 变长字符串优先使用VARCHAR
- 金融数据必须使用DECIMAL避免精度丢失
2.3 完整的数据表创建示例
下面是一个电商系统中用户表的创建示例:
sql复制CREATE TABLE IF NOT EXISTS users (
user_id INT UNSIGNED NOT NULL AUTO_INCREMENT,
username VARCHAR(50) NOT NULL,
password CHAR(60) NOT NULL COMMENT '存储bcrypt哈希值',
email VARCHAR(100) NOT NULL,
phone VARCHAR(20),
register_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
last_login DATETIME,
status TINYINT NOT NULL DEFAULT 1 COMMENT '0-禁用 1-正常',
PRIMARY KEY (user_id),
UNIQUE KEY (username),
UNIQUE KEY (email),
INDEX (phone)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户基本信息表';
这个示例展示了多种实用技巧:
- 使用UNSIGNED避免负数ID
- AUTO_INCREMENT实现自增主键
- COMMENT添加注释说明
- DEFAULT设置默认值
- 创建了主键、唯一索引和普通索引
3. 数据完整性约束深度解析
3.1 实体完整性实现
实体完整性通过主键约束和唯一约束实现,确保每行数据的唯一性。
主键约束特点:
- 每个表只能有一个主键
- 主键列不能为NULL
- 主键值必须唯一
- 可以是单列或多列组合(复合主键)
创建主键的两种方式:
sql复制-- 列级约束
CREATE TABLE products (
product_id INT PRIMARY KEY,
name VARCHAR(100)
);
-- 表级约束
CREATE TABLE order_items (
order_id INT,
product_id INT,
quantity INT,
PRIMARY KEY (order_id, product_id)
);
唯一约束特点:
- 允许NULL值(但只能有一个NULL)
- 一个表可以有多个唯一约束
- 系统会自动创建唯一索引
添加唯一约束示例:
sql复制ALTER TABLE users ADD CONSTRAINT uk_user_phone UNIQUE (phone);
3.2 参照完整性实现
参照完整性通过外键约束实现,确保表间关系的正确性。外键约束要点:
- 被引用表必须存在且有主键
- 外键列和被引用列数据类型必须兼容
- 可以定义级联操作(ON DELETE/UPDATE)
完整的外键创建示例:
sql复制CREATE TABLE orders (
order_id INT PRIMARY KEY,
user_id INT,
order_date DATETIME,
FOREIGN KEY (user_id) REFERENCES users(user_id)
ON DELETE RESTRICT
ON UPDATE CASCADE
);
常用的参照动作:
- RESTRICT:拒绝删除/更新(默认)
- CASCADE:级联删除/更新
- SET NULL:设为NULL
- NO ACTION:与RESTRICT类似
3.3 用户定义完整性
用户定义完整性包括非空约束、CHECK约束和默认值等。
非空约束:
sql复制CREATE TABLE employees (
emp_id INT PRIMARY KEY,
emp_name VARCHAR(50) NOT NULL,
hire_date DATE NOT NULL
);
CHECK约束(MySQL 8.0+支持):
sql复制CREATE TABLE products (
product_id INT PRIMARY KEY,
price DECIMAL(10,2) CHECK (price > 0),
stock INT CHECK (stock >= 0)
);
默认值:
sql复制CREATE TABLE logs (
log_id INT PRIMARY KEY,
log_time DATETIME DEFAULT CURRENT_TIMESTAMP,
level VARCHAR(10) DEFAULT 'INFO'
);
4. 约束管理高级技巧
4.1 约束的命名与查看
为约束命名便于后续管理:
sql复制CREATE TABLE students (
stu_id INT,
stu_name VARCHAR(50),
CONSTRAINT pk_students PRIMARY KEY (stu_id),
CONSTRAINT uk_student_name UNIQUE (stu_name)
);
查看表约束信息:
sql复制SELECT * FROM information_schema.TABLE_CONSTRAINTS
WHERE TABLE_SCHEMA = 'your_db' AND TABLE_NAME = 'your_table';
4.2 约束的修改与删除
删除主键约束(必须先删除自增属性):
sql复制ALTER TABLE products MODIFY product_id INT;
ALTER TABLE products DROP PRIMARY KEY;
删除外键约束:
sql复制ALTER TABLE orders DROP FOREIGN KEY orders_ibfk_1;
添加新约束:
sql复制ALTER TABLE employees ADD CONSTRAINT chk_salary CHECK (salary > 0);
4.3 约束使用的最佳实践
- 命名规范:采用"约束类型_表名_列名"格式,如fk_orders_user_id
- 外键索引:MySQL会自动为外键创建索引,但复合外键可能需要额外优化
- 性能考量:大量外键会影响写入性能,高并发系统可考虑应用层保证数据完整性
- 级联操作:谨慎使用CASCADE,可能引发意外的数据删除
- 延迟检查:某些场景可使用SET FOREIGN_KEY_CHECKS=0临时禁用外键检查
5. 实战中的常见问题与解决方案
5.1 自增主键的坑
问题1:自增列达到最大值后会怎样?
解决方案:使用足够大的数据类型(如BIGINT),或定期归档旧数据
问题2:自增值不连续
这是正常现象,业务代码不应依赖自增ID的连续性
5.2 外键约束失败排查
常见错误及解决方法:
-
错误1452:无法添加外键约束
- 检查被引用表和列是否存在
- 检查数据类型是否匹配
- 确保被引用列有索引
-
错误1215:无法添加外键
- 检查存储引擎是否为InnoDB
- 检查字符集和排序规则是否一致
5.3 字符集问题处理
乱码问题:
- 确保连接字符集与数据库字符集一致
- 建表时显式指定字符集
- 对于已有数据的表,转换要谨慎:
sql复制ALTER TABLE table_name CONVERT TO CHARACTER SET utf8mb4;
5.4 大型表的约束管理
对于海量数据表,添加约束可能很耗时:
- 先在应用层保证数据质量
- 使用pt-online-schema-change等工具在线修改
- 在业务低峰期执行ALTER TABLE
6. 性能优化与设计建议
6.1 索引与约束的关系
- 主键和唯一约束会自动创建索引
- 外键列也应该有索引(MySQL自动创建)
- 复合约束的列顺序影响索引效率
6.2 约束对性能的影响
- 约束检查会增加写入开销
- 外键会导致额外的锁等待
- 在批量导入数据时可临时禁用约束:
sql复制SET FOREIGN_KEY_CHECKS=0;
-- 执行导入操作
SET FOREIGN_KEY_CHECKS=1;
6.3 数据库设计规范
- 每个表必须有主键
- 使用有意义的字段名和注释
- 避免使用保留字作为标识符
- 遵循一致的命名约定(如snake_case)
- 为重要表添加创建时间和更新时间戳:
sql复制CREATE TABLE example (
id INT PRIMARY KEY,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
);
在实际项目中,我通常会先使用工具(如MySQL Workbench)设计ER图,确认所有关系和约束后再生成DDL语句。对于复杂系统,建议将数据库变更脚本纳入版本控制,并使用迁移工具(如Flyway)管理数据库演进。
