3. 关系型数据库基础
说实话,很多做配方管理的人一开始都怕数据库。觉得那是DBA的事。我以前也这么想。
直到有一次,我手工维护的Excel配方表因为同事误操作,整整一周的数据全乱了。那天晚上我加班到凌晨两点,一边恢复数据一边骂自己——为什么不早点学数据库?
嗯,从那以后我明白了:配方数据是工厂的命根子,必须用靠谱的方式存。关系型数据库,就是那个靠谱的底子。
3.1 为什么配方数据需要关系型数据库?
你想想看,一个配方包含什么?原料列表、工艺参数、版本号、有效期、质检标准……这些数据之间有明确的关联关系。Excel能存,但查起来慢,容易出错,多人协作更是灾难。
关系型数据库用表来存数据,用关系来连接数据。说白了,就是把配方拆成几个小表格,然后用ID把它们串起来。这样改一个原料,所有用到它的配方自动更新。
核心优势:
- 结构化存储:每个字段有固定类型,不会出现"数字列里混进文字"的尴尬
- 事务支持:要么全部成功,要么全部回滚,不会半路断电丢数据
- 并发控制:多人同时改配方,不会互相覆盖
- 查询能力:想找"所有含酒精成分的配方",一条SQL搞定
3.2 MySQL安装与配置
我个人习惯用MySQL 8.0以上版本。为什么?窗口函数、CTE这些新特性,做配方分析时特别好用。
3.2.1 安装步骤(Windows环境)
- 去MySQL官网下载MySQL Installer for Windows
- 选择"Developer Default"安装类型
- 设置root密码(记好了,忘了很麻烦)
- 选择"Use Legacy Authentication Method"(兼容性好)
- 一路Next,完成安装
小技巧:安装时勾选"Configure MySQL as a Windows Service",这样MySQL开机自动启动,省心。
3.2.2 验证安装
打开命令行,输入:
mysql -u root -p
输入密码后,看到 mysql> 提示符,说明安装成功。
3.2.3 基础配置
我个人习惯改两个配置:
- 字符集:设为utf8mb4,支持中文和emoji(配方备注里偶尔会用到)
- 时区:设为+8:00,避免时间记录混乱
在MySQL命令行里执行:
SET GLOBAL character_set_server = utf8mb4;
SET GLOBAL time_zone = '+8:00';
注意:生产环境不要直接改全局配置。用配置文件my.ini改,重启服务生效。我曾经在客户服务器上直接SET GLOBAL,结果人家跑着的应用全断了……嗯,从那以后我改配置前都会先问一句"现在能重启吗?"
3.3 SQL语言入门
SQL,全称Structured Query Language。说白了就是跟数据库对话的语言。你告诉它"我要什么数据",它给你查出来。
SQL分四大类:
| 分类 | 全称 | 常用命令 | 用途 |
|---|---|---|---|
| DDL | Data Definition Language | CREATE, ALTER, DROP | 定义数据库结构 |
| DML | Data Manipulation Language | INSERT, UPDATE, DELETE | 操作数据 |
| DQL | Data Query Language | SELECT | 查询数据 |
| DCL | Data Control Language | GRANT, REVOKE | 权限控制 |
做配方管理,最常用的是DML和DQL。DDL只在建表时用一次,DCL基本用不到。
3.4 创建配方数据库与表
好,现在动手。我们创建一个叫 recipe_db 的数据库,专门存配方数据。
3.4.1 创建数据库
CREATE DATABASE recipe_db
CHARACTER SET utf8mb4
COLLATE utf8mb4_unicode_ci;
为什么要指定 utf8mb4_unicode_ci?因为这种排序规则对中文友好,查"面粉"和"麵粉"时不会因为简繁体出问题。
3.4.2 选择数据库
USE recipe_db;
3.4.3 创建配方主表
配方主表存的是配方的基本信息。每个配方一条记录。
CREATE TABLE recipes (
id INT AUTO_INCREMENT PRIMARY KEY,
recipe_name VARCHAR(100) NOT NULL,
version VARCHAR(20) NOT NULL,
product_code VARCHAR(50),
status ENUM('draft', 'active', 'archived') DEFAULT 'draft',
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
);
关键点解释:
AUTO_INCREMENT:自动生成ID,不用手动管ENUM:限制状态只能取三个值,避免脏数据ON UPDATE CURRENT_TIMESTAMP:更新时自动记时间,省得自己写
3.4.4 创建配方原料表
一个配方有多个原料。所以原料表要跟配方主表关联。
CREATE TABLE recipe_ingredients (
id INT AUTO_INCREMENT PRIMARY KEY,
recipe_id INT NOT NULL,
ingredient_name VARCHAR(100) NOT NULL,
quantity DECIMAL(10, 3) NOT NULL,
unit VARCHAR(20) NOT NULL,
FOREIGN KEY (recipe_id) REFERENCES recipes(id)
ON DELETE CASCADE
);
FOREIGN KEY 就是外键。它保证了:
- 你添加原料时,必须指定一个存在的配方ID
- 你删除配方时,它下面的原料自动跟着删(
ON DELETE CASCADE)
经验之谈:外键虽然好用,但数据量大了会影响性能。我一般在开发环境用外键保证数据一致性,生产环境如果表特别大,会考虑用应用层逻辑代替外键。
3.4.5 创建工艺参数表
每个配方还有工艺参数:温度、时间、压力……
CREATE TABLE recipe_parameters (
id INT AUTO_INCREMENT PRIMARY KEY,
recipe_id INT NOT NULL,
param_name VARCHAR(50) NOT NULL,
param_value VARCHAR(100) NOT NULL,
param_unit VARCHAR(20),
FOREIGN KEY (recipe_id) REFERENCES recipes(id)
ON DELETE CASCADE
);
3.5 知识体系总览
下面这张图,把本章的核心逻辑串起来了。你一看就明白:
3.6 验证表结构
表建好了,怎么确认没问题?用 DESCRIBE 命令:
DESCRIBE recipes;
DESCRIBE recipe_ingredients;
DESCRIBE recipe_parameters;
你会看到每个字段的详细信息:类型、是否为空、默认值……
小技巧:用 SHOW CREATE TABLE recipes\G 可以看建表语句的完整版。我经常用这个命令在测试环境和生产环境之间同步表结构。
3.7 插入一条测试数据
表建好了,插条数据试试:
INSERT INTO recipes (recipe_name, version, product_code, status)
VALUES ('经典洗发水配方', 'V1.0', 'SH-001', 'active');
INSERT INTO recipe_ingredients (recipe_id, ingredient_name, quantity, unit)
VALUES (1, '去离子水', 500.000, 'kg'),
(1, '月桂醇聚醚硫酸酯钠', 120.000, 'kg'),
(1, '椰油酰胺丙基甜菜碱', 80.000, 'kg');
INSERT INTO recipe_parameters (recipe_id, param_name, param_value, param_unit)
VALUES (1, '搅拌温度', '75', '℃'),
(1, '搅拌时间', '30', 'min'),
(1, 'pH值', '6.5', '');
查一下数据:
SELECT * FROM recipes;
SELECT * FROM recipe_ingredients WHERE recipe_id = 1;
SELECT * FROM recipe_parameters WHERE recipe_id = 1;
看到数据了?嗯,这就是关系型数据库的威力。三张表,通过ID关联,把配方的完整信息存得清清楚楚。
避坑指南:我曾经在生产环境直接执行INSERT,结果发现少写了一个字段,数据插进去了但值是NULL。后来查问题查了半天。所以我的习惯是:先在测试环境跑一遍SQL,确认没问题再上生产。别嫌麻烦,这习惯救过我很多次。
好了,MySQL装好了,数据库建好了,表也创建成功了。你现在已经掌握了配方数据存储的底层能力。接下来,就是往这些表里填真实数据,然后用SQL去分析它们。