《零基础学PHP:从入门到实战》教程-模块七:MySQL 数据库基础-3

第 3 章:深入数据管理:表结构设计与高级查询

章节介绍

章节学习目标

通过本章的学习,你将能够:

  1. 理解 MySQL 中常用的数据类型及其适用场景,为字段选择正确的类型。
  2. 掌握主键、自增、唯一、非空等数据完整性约束的使用,设计出健壮的数据表结构。
  3. 熟练运用WHEREORDER BYLIMIT子句进行复杂的数据筛选、排序和分页查询。
  4. 使用COUNTSUMAVG等聚合函数对数据进行统计和分析。
  5. 使用ALTER TABLE语句对已存在的表结构进行修改和优化。

在整个教程中的作用

本章是数据库学习从"会用"到"用好"的关键转折点。如果说第 2 章教会了你如何与数据库"对话"(CRUD),那么本章则教你如何设计高效的"对话规则"(表结构)并提出更复杂的"问题"(高级查询)。扎实的表结构设计能力和灵活的查询技巧,是构建任何稳定、高效数据驱动应用的基石,也是后续学习 PHP 连接数据库、进行多表操作(第 4、5 章)必不可少的前提。

与前面章节的衔接

在第 2 章中,我们创建了一个简单的users表并进行了基本的增删改查操作。但那个表存在明显缺陷:ID 可以重复、用户名和邮箱也可能重复,这在实际应用中是完全不可接受的。本章,我们将首先优化第 2 章的users,为其添加必要的约束,使其更符合实际业务需求。然后,我们将在此基础上,学习如何提出更精确、更高效的查询。

本章主要内容概览

  1. 精雕细琢:字段与约束------深入讲解数字、字符串、日期时间等数据类型,以及保障数据正确性的各种约束(主键、自增、唯一、非空)。
  2. 精准获取:高级查询技巧 ------学习使用WHERE进行多条件过滤,使用ORDER BY对结果排序,使用LIMIT实现分页,这是 Web 应用列表展示的核心。
  3. 统览全局:聚合函数 ------学习使用COUNTMAXAVG等函数对数据进行统计汇总,生成报表或仪表盘数据。
  4. 与时俱进:修改表结构 ------掌握如何使用ALTER TABLE在项目迭代中安全地修改已有表的结构。

核心概念讲解

1. 字段数据类型详解

数据类型定义了列可以存储何种数据。选择正确的类型至关重要,它影响数据的完整性、查询效率以及存储空间。

数值类型
  • 整数类型TINYINT, SMALLINT, MEDIUMINT, INT(或INTEGER), BIGINT。区别在于存储范围。INT是最常用的。
  • INT(11)中的11是显示宽度,不影响存储,通常可不指定。
  • 浮点数类型FLOAT, DOUBLE。用于存储小数,但可能存在精度丢失(浮点运算通病)。
  • 定点数类型DECIMAL(M, D)。用于存储精确的小数,如财务数据。M是总位数,D是小数点后的位数。DECIMAL(10, 2)可存储类似12345678.12的数字。
字符串类型
  • 定长字符串CHAR(n)。无论实际内容多少,都占用n个字符的存储空间。查询速度快,适合存储长度固定的数据,如国家代码('CN', 'US')。
  • 变长字符串VARCHAR(n)。根据实际内容长度占用存储空间,最大长度为n。节省空间,适合存储长度变化大的数据,如用户名、文章标题。n指的是字符数,而非字节数(与字符集有关)
  • 文本类型TINYTEXT, TEXT, MEDIUMTEXT, LONGTEXT。用于存储大量文本,如文章内容、日志。选择时根据可能的最大文本长度决定。
日期时间类型
  • DATE:仅存储日期,格式'YYYY-MM-DD'。
  • TIME:仅存储时间,格式'HH:MM:SS'。
  • DATETIME:存储日期和时间,格式'YYYY-MM-DD HH:MM:SS'。范围从 1000 年到 9999 年。
  • TIMESTAMP:存储时间戳(从'1970-01-01 00:00:01' UTC 至今的秒数)。范围到 2038 年。会自动根据服务器时区进行转换,并且可以设置自动更新(如记录修改时间)
    最佳实践 :优先选择能满足需求的最小数据类型。例如,年龄用TINYINT UNSIGNED(0-255),文章状态用TINYINT,电话号码用VARCHAR(20)而非CHAR(20)

2. 数据完整性约束

约束是应用于表列上的规则,用于限制其中数据的类型,确保数据的准确性和可靠性。

  • 主键约束 (PRIMARY KEY)
  • 作用 :唯一标识表中的每一行记录。一张表只能有一个主键
  • 特性 :值必须唯一非空 (NOT NULL)。
  • 选择 :通常是一个没有业务意义的自增数字(代理主键),如id。这比使用有意义的字段(如身份证号)作为主键更灵活。
  • 自增属性 (AUTO_INCREMENT)
  • 作用:通常与整数型主键结合使用。当插入新记录时,数据库会自动为该字段生成一个唯一且递增的值。
  • 注意:删除记录后,自增值不会回溯。事务回滚也可能导致自增值"浪费"。
  • 唯一约束 (UNIQUE)
  • 作用 :确保列中所有值都是不同的。与主键的区别在于,唯一键允许存在多个NULL值(取决于数据库具体实现,MySQL 中唯一键允许多个 NULL),且一张表可以有多个唯一键。
  • 应用场景:用户名、邮箱、手机号等需要唯一但非标识性的字段。
  • 非空约束 (NOT NULL)
  • 作用 :强制列不接受NULL值。插入或更新数据时,该字段必须有值。
  • 最佳实践 :对于业务上必须存在的字段,如用户名、创建时间,应显式设置为NOT NULL
  • 默认值 (DEFAULT)
  • 作用:当插入数据未指定该列值时,自动填充一个预设值。
  • 应用场景status字段默认为 1(启用),created_at字段默认为当前时间。

3. SELECT 语句的深入:WHERE, ORDER BY, LIMIT

  • WHERE子句 :用于过滤记录。支持使用=<>!=><>=<=BETWEEN(范围)、LIKE(模糊匹配)、IN(值列表)等操作符。可以使用ANDORNOT来组合多个条件。
  • LIKE操作符%代表零个、一个或多个字符;_代表一个单一字符。LIKE '张%'匹配所有姓张的记录。
  • ORDER BY子句 :用于对结果集进行排序。ASC为升序(默认),DESC为降序。可以按多个字段排序。
  • LIMIT子句 :用于限制返回的记录数。LIMIT n返回前 n 条;LIMIT m, n跳过前 m 条,返回接下来的 n 条。这是实现分页功能的核心LIMIT (页码-1)*每页条数, 每页条数

4. 聚合函数

聚合函数对一组值执行计算,并返回单个值。常与GROUP BY子句(将在第 5 章详细讲解)结合使用。

  • COUNT():返回匹配指定条件的行数。COUNT(*)计数所有行,COUNT(column)计数该列非 NULL 值的行数。
  • SUM():返回数值列的总和。
  • AVG():返回数值列的平均值。
  • MAX() / MIN():返回列的最大/最小值。
  • 注意 :聚合函数会忽略NULL值(COUNT(*)除外)。

代码示例

示例 1:创建带有完整约束的优化 users 表

sql 复制代码
-- 首先,如果存在旧的简单users表,先删除它(仅用于演示,生产环境请谨慎操作)
-- DROP TABLE IF EXISTS users;

-- 创建优化的 users 表
CREATE TABLE users (
    id INT UNSIGNED NOT NULL AUTO_INCREMENT, -- 无符号整数,非空,自增
username VARCHAR(50) NOT NULL UNIQUE,    -- 用户名,变长字符串,非空,唯一
email VARCHAR(100) NOT NULL UNIQUE,      -- 邮箱,变长字符串,非空,唯一
`password` CHAR(60) NOT NULL,            -- 密码(存储Bcrypt或Argon2哈希值),定长60字符
age TINYINT UNSIGNED,                    -- 年龄,微小无符号整数,允许为空
status TINYINT DEFAULT 1 NOT NULL,       -- 状态:1启用,0禁用。默认值为1,非空
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, -- 创建时间,默认值为当前时间戳
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, -- 更新时间,默认当前时间,且更新时自动设置为当前时间
PRIMARY KEY (id)                         -- 将id字段设为主键
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; -- 使用InnoDB引擎和UTF8MB4字符集

注释说明

  • INT UNSIGNED:确保 ID 为正数。
  • CHAR(60) for password:常见的密码哈希算法(如 Bcrypt)输出长度固定。
  • DEFAULT CURRENT_TIMESTAMP:插入时自动填充当前时间。
  • ON UPDATE CURRENT_TIMESTAMP:记录更新时,自动将本字段更新为当前时间。
  • ENGINE=InnoDB:支持事务、外键,是 MySQL 默认及推荐引擎。
  • CHARSET=utf8mb4:支持完整的 UTF-8 字符集(包括 Emoji 表情)。

示例 2:插入测试数据并演示约束

sql 复制代码
-- 插入第一条数据,id将自动生成(如1)
INSERT INTO users (username, email, `password`, age) VALUES
('张三', 'zhangsan@example.com', '$2y$10$SomeHashValue...', 25);

-- 插入第二条数据
INSERT INTO users (username, email, `password`) VALUES
('李四', 'lisi@example.com', '$2y$10$AnotherHash...');
-- age未提供,将为NULL;status和created_at/updated_at将使用默认值。
-- 尝试插入重复用户名,将失败并报错:Duplicate entry '张三' for key 'username'
-- INSERT INTO users (username, email, `password`) VALUES ('张三', 'zhangsan2@example.com', 'hash');

-- 尝试插入NULL到username,将失败并报错:Column 'username' cannot be null
-- INSERT INTO users (username, email, `password`) VALUES (NULL, 'test@example.com', 'hash');

示例 3:使用 WHERE 子句进行多条件查询

sql 复制代码
-- 查询所有状态为启用(status=1)的用户
SELECT * FROM users WHERE status = 1;

-- 查询年龄大于20且状态为启用的用户
SELECT id, username, age FROM users WHERE age > 20 AND status = 1;

-- 查询用户名为"张三"或邮箱以"lisi"开头的用户
SELECT * FROM users WHERE username = '张三' OR email LIKE 'lisi%';

-- 查询年龄在20到30之间(包含)的用户
SELECT * FROM users WHERE age BETWEEN 20 AND 30;
-- 等价于
SELECT * FROM users WHERE age >= 20 AND age <= 30;

-- 查询状态为1或3的用户
SELECT * FROM users WHERE status IN (1, 3);

示例 4:使用 ORDER BY 和 LIMIT 进行排序与分页

sql 复制代码
-- 按创建时间降序排列(最新注册的在前)
SELECT username, email, created_at FROM users ORDER BY created_at DESC;

-- 先按状态升序,状态相同的按年龄降序排列
SELECT username, status, age FROM users ORDER BY status ASC, age DESC;

-- 获取最早注册的3个用户
SELECT username, created_at FROM users ORDER BY created_at ASC LIMIT 3;

-- 模拟分页:每页显示2条数据,获取第2页的数据(即第3、4条记录)
-- 假设已有数据:id为1,2,3,4,5...
SELECT id, username FROM users ORDER BY id ASC LIMIT 2 OFFSET 2; -- 跳过前2条,取2条
-- 更常见的写法:LIMIT offset, row_count
SELECT id, username FROM users ORDER BY id ASC LIMIT 2, 2; -- 从第2条之后开始(即第3条),取2条

分页公式应用LIMIT (page - 1) * page_size, page_size

示例 5:使用聚合函数进行数据统计

sql 复制代码
-- 统计用户总数量
SELECT COUNT(*) AS total_users FROM users;

-- 统计提供了年龄信息的用户数量(忽略age为NULL的行)
SELECT COUNT(age) AS users_with_age FROM users;

-- 计算所有用户的平均年龄(NULL值不参与计算)
SELECT AVG(age) AS average_age FROM users;

-- 找到最大和最小的年龄
SELECT MAX(age) AS max_age, MIN(age) AS min_age FROM users;

-- 结合WHERE使用:统计状态为启用的用户数量
SELECT COUNT(*) AS active_users FROM users WHERE status = 1;

示例 6:使用 ALTER TABLE 修改表结构

sql 复制代码
-- 为现有users表添加一个'avatar'(头像URL)字段
ALTER TABLE users ADD COLUMN avatar VARCHAR(255) DEFAULT NULL COMMENT '用户头像存储路径';

-- 修改'email'字段的长度从100到150
ALTER TABLE users MODIFY COLUMN email VARCHAR(150) NOT NULL UNIQUE;

-- 为'age'字段添加一个检查约束(MySQL 8.0.16+ 支持 CHECK)
-- ALTER TABLE users ADD CONSTRAINT chk_age CHECK (age >= 0 AND age <= 150);

-- 删除'avatar'字段(谨慎操作!)
-- ALTER TABLE users DROP COLUMN avatar;

-- 重命名表
-- ALTER TABLE users RENAME TO members;

重要提示 :在生产环境修改大表结构(如添加列、修改类型)可能会锁表并影响服务,需在低峰期进行,并考虑使用ALGORITHM=INPLACE, LOCK=NONE等在线 DDL 选项(如果存储引擎支持)。

实战项目:用户中心管理系统(表结构优化与复杂查询)

项目需求分析

我们将优化并扩展第 2 章简单的用户表,模拟一个用户中心后台管理系统的数据层。管理员需要能够:

  1. 管理用户:查看用户列表(支持分页、按状态/注册时间筛选排序)、查看用户详情、搜索用户。
  2. 数据分析:了解用户总体情况(总人数、平均年龄、年龄分布等)。

技术方案

  1. 数据库设计 :创建符合规范的users表(使用示例 1 的优化结构)。
  2. 数据准备:使用 SQL 脚本批量插入至少 20 条模拟数据,覆盖不同状态、年龄和注册时间。
  3. 复杂查询实现:编写一系列 SQL 查询语句,实现上述管理功能。

分步骤实现

步骤 1:创建优化的 users 表

(代码同示例 1
步骤 2:插入模拟数据

sql 复制代码
-- 使用存储过程或多次INSERT批量生成数据(此处简化,手动插入多条)
INSERT INTO users (username, email, `password`, age, status) VALUES
('王五', 'wangwu@example.com', 'hash1', 30, 1),
('赵六', 'zhaoliu@example.com', 'hash2', NULL, 1),
('钱七', 'qianqi@example.com', 'hash3', 22, 0),
('孙八', 'sunba@example.com', 'hash4', 35, 1),
('周九', 'zhoujiu@example.com', 'hash5', 28, 1),
('吴十', 'wushi@example.com', 'hash6', 40, 1),
('郑十一', 'zhengshiyi@example.com', 'hash7', 19, 0),
... -- 可继续添加更多数据,或使用脚本生成
('测试用户20', 'user20@test.com', 'hash20', 26, 1);

步骤 3:实现后台管理查询

sql 复制代码
-- 1. 基础用户列表(分页查询):获取第1页,每页5条,按注册时间倒序
SELECT id, username, email, age, status, created_at
FROM users
ORDER BY created_at DESC
LIMIT 0, 5;

-- 2. 条件筛选列表:查找所有状态为启用(1)且年龄大于25岁的用户,按年龄升序
SELECT id, username, age, email
FROM users
WHERE status = 1 AND age > 25
ORDER BY age ASC;

-- 3. 用户搜索:根据用户名或邮箱模糊搜索
SELECT id, username, email
FROM users
WHERE username LIKE '%张%' OR email LIKE '%example%';

-- 4. 数据统计面板:一次性获取多个统计指标
SELECT
    COUNT(*) AS total_users,
    COUNT(age) AS users_with_age,
    AVG(age) AS avg_age,
    SUM(status = 1) AS active_users, -- 技巧:条件求和
MIN(created_at) AS first_registration,
    MAX(created_at) AS latest_registration
FROM users;

-- 5. 年龄分布统计(简单版):统计各年龄段的用户数(使用CASE WHEN)
SELECT
    CASE
        WHEN age < 20 THEN '20岁以下'
        WHEN age BETWEEN 20 AND 29 THEN '20-29岁'
        WHEN age BETWEEN 30 AND 39 THEN '30-39岁'
        ELSE '40岁及以上或未填写'
    END AS age_group,
    COUNT(*) AS user_count
FROM users
GROUP BY age_group -- GROUP BY将在第5章详解,此处先做了解
ORDER BY user_count DESC;

项目测试和部署指南

  1. 测试:在 MySQL 命令行或 Workbench 中逐一执行上述 SQL 语句,检查结果是否符合预期(如分页是否正确、条件筛选是否准确、统计数字是否计算正确)。
  2. 部署 :将这些 SQL 语句(CREATE TABLE, INSERT, 各个SELECT查询)保存为.sql文件。在实际项目部署时,可通过以下方式执行:
  • 在 MySQL 客户端中使用 source /path/to/your_script.sql
    • 在 PHPMyAdmin 中导入。
  • 在 PHP 部署脚本中使用mysqli::multi_query()(需注意安全)。

项目扩展和优化建议

  1. 添加索引 :在username, email, status, created_at等常用于查询条件的字段上创建索引,可以极大提升查询速度(索引是后续高级主题)。
sql 复制代码
    CREATE INDEX idx_status ON users(status);
    CREATE INDEX idx_created_at ON users(created_at);
  1. 实现更复杂的分页 :当前的分页在数据量极大时,LIMIT offset, noffset很大会导致性能下降。可考虑使用"基于游标的分页"(如WHERE id > last_id LIMIT n)。
  2. 准备 PHP 接口 :思考每个SELECT查询如何对应到一个 PHP 后台管理页面功能(列表 API、搜索 API、统计 API),为第 4 章的学习做好准备。

最佳实践

1. 表结构设计规范

  • 命名规范 :表名、字段名使用小写字母、数字和下划线,见名知意。例如order_detail, created_at
  • 选择合适的主键 :优先使用与业务无关的自增整数(BIGINT AUTO_INCREMENT),为未来留足空间。
  • 为字段添加注释 :使用COMMENT关键字说明字段用途,便于团队协作和维护。
sql 复制代码
    `status` TINYINT DEFAULT 1 COMMENT '用户状态:0-禁用,1-启用,2-未激活'
  • 指定字符集和排序规则 :统一使用utf8mb4utf8mb4_unicode_ci(对多语言支持更好),避免乱码。
  • 使用NOT NULL约束:明确字段是否允许为空,能简化程序逻辑并避免歧义。

2. 查询性能与安全初步认知(为第 4 章铺垫)

  • SELECT * 的陷阱 :尽量指定需要的列,而不是使用SELECT *。这可以减少网络传输的数据量,并可能利用覆盖索引提升性能。
  • SELECT * FROM users WHERE ...
    • SELECT id, username, email FROM users WHERE ...
  • 模糊查询LIKE前缀LIKE '%关键字%'会导致全表扫描,性能极差。如果业务允许,尽量使用LIKE '关键字%'(前缀匹配)。
  • 安全警示:SQL 注入根源 :本章的 SQL 都是静态或手动拼接的。当在 PHP 中动态拼接 SQL 时,如果用户输入未经处理就直接嵌入 SQL 字符串,将导致致命的 SQL 注入漏洞
sql 复制代码
    -- 假设PHP中这样拼接(危险!):
-- $sql = "SELECT * FROM users WHERE username = '" . $_POST['username'] . "'";
    -- 如果用户输入:`admin' OR '1'='1`
    -- 最终SQL变为:
SELECT * FROM users WHERE username = 'admin' OR '1'='1'; -- 这将返回所有用户!
复制代码
-   **防护方案**:**绝对不要直接拼接SQL!** 在第4章,我们将学习使用**预处理语句 (Prepared Statements)** 来彻底解决此问题。

3. 常见错误和避坑指南

  • 混淆CHARVARCHARCHAR定长,浪费存储但速度快;VARCHAR变长,节省存储但稍有开销。根据数据特征选择。
  • 错误使用FLOAT/DOUBLE存储精确数值 :财务、科学计算等需要精确值的场景,必须使用DECIMAL
  • NULL值的比较 :在 SQL 中,NULL = NULL的结果是NULL(假),判断是否为NULL应使用IS NULLIS NOT NULL
  • LIMIT分页的性能问题:如前所述,大数据量下深分页性能差,需要设计更优的分页策略。

练习题与挑战

基础练习题

  1. 【难度:★☆☆☆☆】数据类型选择
    设计一个products(产品)表,需存储以下信息:自增 ID、产品名称(最多 100 字符)、产品描述(可能很长)、价格(精确到分)、库存数量、是否上架(是/否)、创建时间。请写出CREATE TABLE语句。
  2. 【难度:★☆☆☆☆】约束应用
    在上题创建的products表中,如何确保:1) 产品名称不能重复;2) 价格和库存不能为负数;3) 创建时间自动记录?请修改或补充你的CREATE TABLE语句。
  3. 【难度:★★☆☆☆】条件查询
    假设users表如本章所定义。编写 SQL 查询:
    a) 找出所有邮箱包含"gmail.com"的用户。
    b) 找出年龄未填写(NULL)或者状态为禁用(status=0)的用户。
    c) 找出在 2023 年注册的用户。(提示:使用YEAR(created_at) = 2023created_at BETWEEN '2023-01-01' AND '2023-12-31'

进阶练习题

  1. 【难度:★★☆☆☆】排序与分页
    继续使用users表。编写 SQL 实现一个"用户管理列表"接口,要求:可按注册时间(created_at)降序或年龄(age)升序排序(前端传入一个排序参数),并支持分页(传入页码和每页大小)。请写出一个可以应对不同排序要求的查询语句结构。(提示:使用ORDER BY 动态字段)
  2. 【难度:★★★☆☆】聚合函数与分组
    products表(假设已有很多数据)中,编写 SQL:
    a) 计算所有上架产品的平均价格。
    b) 统计每个"是否上架"状态下的产品数量。
    c) (挑战)找出价格高于平均价格的所有产品。

综合挑战题

  1. 【难度:★★★☆☆】小型博客系统表结构设计
    为一个简单的博客系统设计数据库表,需满足:
  • 用户可以注册登录(users表已存在)。
  • 文章(articles)有标题、内容、摘要、封面图、作者(关联用户 ID)、所属分类(关联分类 ID)、发布状态(草稿/已发布)、浏览量、发布时间。
  • 分类(categories)有名称、描述。
  • 文章可以有多个标签,一个标签可以属于多篇文章(多对多关系,需要中间表article_tag)。
  • 请写出articles, categories, tags, article_tag四张表的CREATE TABLE语句,明确定义字段类型、主键、外键(FOREIGN KEY将在第 5 章学习,此处可先标注出来)和必要的约束。

章节总结

本章重点知识回顾

  1. 数据类型是地基 :学会了根据数据特性(整数、小数、短文本、长文本、日期)选择INT, DECIMAL, VARCHAR, TEXT, DATETIME等类型。
  2. 约束是保障 :理解了PRIMARY KEY, AUTO_INCREMENT, UNIQUE, NOT NULL, DEFAULT等约束如何共同作用,确保数据的唯一性、一致性和业务规则的完整性。
  3. 查询是利器 :掌握了使用WHERE进行灵活筛选(包括多条件、模糊匹配、范围查询),使用ORDER BY控制结果顺序,使用LIMIT实现高效分页,以及使用聚合函数(COUNT, AVG, MAX等)进行数据统计分析。
  4. 变更是常态 :学会了使用ALTER TABLE来应对需求变化,安全地添加、修改或删除表字段。

技能掌握要求

完成本章学习后,你应当能够:

  • 独立设计一个符合第三范式基础要求、包含适当数据类型和约束的数据表。
  • 无需查阅文档,熟练编写出实现复杂筛选、排序、分页和数据统计的 SQL 查询语句。
  • 清楚地知道SELECT *的危害、LIKE的性能问题以及 SQL 注入漏洞的成因(虽然防护将在下一章实现)。

进一步学习建议

  • 实践:在本地数据库中,反复练习本章的所有示例代码,并尝试完成练习题,尤其是综合挑战题。
  • 预习 :第 4 章将把 SQL 与 PHP 结合起来。思考一下:如何用 PHP 变量动态替换本章 SQL 语句中的条件值(如WHERE username = '某变量')?这将直接引出对预处理语句的强烈需求。
  • 延伸:如果你对查询性能感兴趣,可以提前搜索"MySQL 索引原理"和"EXPLAIN SQL"进行了解,这将是数据库优化的重要主题。
相关推荐
AL流云。1 小时前
MySQL安装【Centos, Ubuntu, Windows】
mysql·ubuntu·centos
老华带你飞1 小时前
茶叶商城|基于SprinBoot+vue的茶叶商城系统(源码+数据库+文档)
java·前端·javascript·数据库·vue.js·spring boot
我科绝伦(Huanhuan Zhou)1 小时前
Oracle性能优化方法论:从基线建立到问题根治
数据库·oracle·性能优化
菜鸟小九1 小时前
mysql运维(主从复制)
android·运维·mysql
秋邱1 小时前
AR + 离线 AI 实战:YOLOv9+TensorFlow Lite 实现移动端垃圾分类识别
开发语言·前端·数据库·人工智能·python·html
X***07881 小时前
使用bitnamiredis-sentinel部署Redis 哨兵模式
数据库·redis·sentinel
zwm_yy1 小时前
mysql安全优化
数据库·mysql·adb
爱可生开源社区1 小时前
SQLShift V5.0 发布!引入增强模型:复杂 SQL 转换准确率质变
数据库·sql