数据库与表的创建:DDL基础

引言 提出问题 安装好MySQL后,你可能迫不及待想要存储数据。但是: 如何创建一个数据库? 如何创建表来存储用户信息、订单数据? 表创建后发现字段设计不合理,如何修改? 如何删除不需要的表和数据库? DDL、DML、DQL这些术语是什么意思? 这篇文章将带你掌握MySQL的"数据定义语言",学会管理数据库对象的生命周期! 为什么重要 DDL(Data Definition Language)是使用MySQL的第一步: ✅ 没有数据库和表,就无法存储数据 ✅ 合理的表结构设计,是性能优化的基础 ✅ 掌握ALTER语句,应对需求变更 ✅ 了解DROP的风险,避免误删数据 基础概念 SQL语言的分类 SQL(Structured Query Language,结构化查询语言)按功能分为四大类: 1. DDL(Data Definition Language,数据定义语言) 作用:定义和管理数据库对象(数据库、表、索引、视图) 核心语句: CREATE:创建数据库对象 ALTER:修改数据库对象 DROP:删除数据库对象 TRUNCATE:清空表数据 RENAME:重命名对象 本文重点讲解DDL! 2. DML(Data Manipulation Language,数据操作语言) 作用:操作表中的数据 核心语句: INSERT:插入数据 UPDATE:更新数据 DELETE:删除数据 (下一篇详细讲解) 3. DQL(Data Query Language,数据查询语言) 作用:查询数据 核心语句: SELECT:查询数据 (SQL进阶篇详细讲解) 4. DCL(Data Control Language,数据控制语言) 作用:管理用户权限 核心语句: GRANT:授予权限 REVOKE:撤销权限 数据库操作 创建数据库(CREATE DATABASE) 基础语法 CREATE DATABASE database_name; 实战示例 -- 创建一个名为 mydb 的数据库 CREATE DATABASE mydb; -- 执行结果 Query OK, 1 row affected (0.01 sec) 指定字符集和校对规则 CREATE DATABASE mydb CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; 参数说明: ...

2025-11-20 · maneng

MySQL安装与环境配置

引言 提出问题 前两篇文章中,我们理解了数据库的重要性和MySQL的核心优势。但是: 如何在自己的电脑上安装MySQL? Windows、Mac、Linux系统的安装方式有什么区别? 如何快速搭建MySQL开发环境(Docker)? 安装后如何连接和使用MySQL? 有哪些好用的MySQL客户端工具? 这篇文章将带你动手实战,从零开始搭建MySQL开发环境! 为什么重要 “工欲善其事,必先利其器”。正确安装和配置MySQL是学习的第一步: ✅ 环境搭建好,后续学习才能顺畅 ✅ 掌握多平台安装,适应不同工作环境 ✅ 了解配置文件,为后续性能调优打基础 ✅ 熟悉客户端工具,提升开发效率 基础概念 MySQL的三种安装方式 方式1:官方安装包(推荐新手) 特点: ✅ 安装简单,图形化界面 ✅ 自动配置环境变量 ✅ 集成MySQL Workbench客户端 ❌ 版本更新需要重新下载安装包 适用场景: 开发环境 学习测试 Windows/macOS用户 方式2:包管理器(推荐Linux用户) 特点: ✅ 命令行一键安装 ✅ 版本更新方便(apt upgrade/yum update) ✅ 自动处理依赖关系 ❌ 版本可能不是最新 适用场景: Linux服务器 CI/CD自动化 开发环境 方式3:Docker容器(推荐进阶用户) 特点: ✅ 环境隔离,不污染主机 ✅ 秒级启动和销毁 ✅ 版本切换方便 ❌ 需要掌握Docker基础 适用场景: 快速测试 多版本切换 微服务开发 Windows系统安装 方式一:MSI安装包(推荐) 步骤1:下载MySQL安装包 访问MySQL官网:https://dev.mysql.com/downloads/mysql/ ...

2025-11-20 · maneng

MySQL简介:历史、特点与应用场景

引言 提出问题 在上一篇文章中,我们理解了为什么需要数据库。但是面对市场上众多的数据库产品,你可能会困惑: 为什么阿里巴巴、腾讯、字节跳动都选择MySQL? MySQL和Oracle有什么区别?为什么Oracle那么贵还有人用? PostgreSQL被称为"最先进的开源数据库",为什么MySQL更流行? 我应该学MySQL还是学其他数据库? 这篇文章将帮你找到答案! 为什么重要 选择正确的数据库,关系到: 技术栈:你的职业发展方向 成本:开源 vs 商业授权(百万级差异) 生态:是否有丰富的工具和社区支持 就业:市场对不同数据库技能的需求 数据说话: DB-Engines排名:MySQL长期稳居第2名(仅次于Oracle) TIOBE指数:MySQL是最受欢迎的开源数据库 招聘数据:MySQL相关岗位是Oracle的3倍 MySQL的诞生与发展 起源:一个瑞典小团队的创业故事(1995年) 1995年,三位瑞典工程师创建了MySQL: Michael “Monty” Widenius David Axmark Allan Larsson 创业初衷:他们需要一个快速、可靠、免费的数据库来支持自己的咨询业务,但当时的商业数据库(如Oracle)太贵,开源数据库(如PostgreSQL)太慢。 命名来源: “My”:Monty女儿的名字 “SQL”:结构化查询语言(Structured Query Language) 有趣的细节:MySQL的海豚Logo名叫"Sakila",来自全球用户投票选出的非洲城市名。 发展历程:从小众到全球第二 阶段一:开源崛起(1995-2000) 1995年5月23日:MySQL 1.0发布 仅支持基本的SQL查询 没有事务支持 但速度快、体积小、免费 关键特性: 采用双授权模式:GPL开源 + 商业授权 专注于速度而非功能完整性 适合Web应用(LAMP架构:Linux + Apache + MySQL + PHP) 阶段二:互联网爆发(2000-2008) 2000年:MySQL 3.23发布 支持全文检索 支持事务(InnoDB存储引擎) 成为互联网公司首选 2003年:MySQL 4.0发布 支持子查询 支持Union 查询缓存 2005年:MySQL 5.0发布 支持存储过程 支持视图 支持触发器 这一时期: ...

2025-11-20 · maneng

什么是数据库?为什么需要数据库?

引言 提出问题 假设你正在开发一个电商网站,需要存储用户信息、商品数据、订单记录。最简单的方式是什么?把数据写入文本文件! users.txt: 1,张三,zhangsan@example.com,18888888888 2,李四,lisi@example.com,13999999999 products.txt: 1,iPhone 15,6999,100 2,MacBook Pro,12999,50 orders.txt: 1,1,1,2024-01-15 10:30:00,6999 2,2,2,2024-01-15 11:45:00,12999 但当你的网站有1000万用户时,你会遇到以下问题: 如何快速查找张三的订单记录?(需要遍历1000万行) 如何保证两个用户不会同时购买最后一件商品?(并发问题) 如果服务器突然断电,刚写入一半的订单数据怎么办?(数据一致性) 如何保证用户密码不会被其他程序随意读取?(安全性) 这就是为什么我们需要数据库! 为什么重要 数据库是现代软件系统的基石: 💰 金融系统:每秒处理上万笔交易,不能有任何差错 🛒 电商平台:双十一期间,亿级用户并发访问 📱 社交媒体:存储数十亿用户的照片、视频、动态 🏥 医疗系统:保存患者病历,关乎生命安全 掌握数据库,你才能: 设计出高效、可靠的系统架构 解决生产环境的性能瓶颈 理解为什么"删库跑路"是工程师最大的噩梦 基础概念 第一性原理:什么是数据? 在计算机科学中,**数据(Data)**是对现实世界信息的抽象表示。 简单类比: 现实世界:一个名叫"张三"的人,身高180cm,体重75kg 数据表示:{"name": "张三", "height": 180, "weight": 75} 数据的本质是结构化的信息,可以被计算机存储、处理和传输。 从文件到数据库的演进 阶段一:纯文本文件(1960年代) 最原始的数据存储方式: users.txt: 张三,男,25,北京 李四,女,30,上海 王五,男,28,深圳 优点: ✅ 简单直观,易于理解 ✅ 不需要额外的软件支持 缺点: ❌ 查询效率低:需要逐行扫描 ❌ 并发问题:多个程序同时写入会数据混乱 ❌ 数据冗余:同一个数据在多个文件中重复存储 ❌ 无法保证一致性:写入一半断电会导致数据损坏 阶段二:层次数据库(1960-1970年代) 数据以树形结构组织: 公司 ├── 研发部 │ ├── 张三(工号001) │ └── 李四(工号002) └── 销售部 ├── 王五(工号003) └── 赵六(工号004) 优点: ...

2025-11-20 · maneng

MySQL第一性原理:为什么我们需要数据库?

引言 “如果你不能简单地解释一件事,说明你还没有真正理解它。” —— 理查德·费曼 作为一名后端开发者,你一定写过这样的代码: @Autowired private UserRepository userRepository; public User findUser(Long id) { return userRepository.findById(id); } 这行代码背后,数据库帮你做了什么? 持久化存储:数据写入磁盘,重启不丢失 快速检索:1亿条数据中找到目标行,只需10微秒 并发控制:1万个并发请求,数据不会错乱 事务保证:转账操作要么全成功,要么全失败 故障恢复:系统崩溃后,数据可以完整恢复 但你有没有想过: 为什么不用文件存储数据?(txt、csv、json) 为什么不用内存存储数据?(HashMap、Redis) 为什么一定要用MySQL这样的关系型数据库? 今天,我们从第一性原理出发,通过对比文件、内存、MySQL三种存储方案,深度剖析数据库解决的核心问题。 本文不会教你怎么写SQL,而是回答为什么需要数据库。 一、引子:用户注册功能的三种实现 让我们从一个最简单的需求开始:用户注册功能。 需求: 用户注册时,存储用户名和密码 检查用户名是否已存在 用户登录时,验证用户名和密码 按注册时间范围查询用户 性能要求: 支持100万用户 注册和登录响应时间 < 100ms 支持1000并发 我们将用三种方式实现,看看它们的差异。 1.1 场景A:文件存储(users.txt) 实现思路:将用户数据存储在文本文件中,每行一个用户,逗号分隔字段。 /** * 用户服务 - 文件存储实现 */ public class FileUserService { private static final String FILE_PATH = "users.txt"; /** * 注册用户(追加到文件末尾) */ public void register(String username, String password) { // 1. 检查用户名是否已存在 if (exists(username)) { throw new RuntimeException("用户名已存在"); } // 2. 追加到文件 try (FileWriter fw = new FileWriter(FILE_PATH, true)) { String line = username + "," + hashPassword(password) + "," + System.currentTimeMillis() + "\n"; fw.write(line); } catch (IOException e) { throw new RuntimeException("注册失败", e); } } /** * 检查用户名是否存在(全文件扫描) */ public boolean exists(String username) { try (BufferedReader br = new BufferedReader(new FileReader(FILE_PATH))) { String line; while ((line = br.readLine()) != null) { // O(n) 全表扫描 String[] parts = line.split(","); if (parts[0].equals(username)) { return true; } } } catch (IOException e) { e.printStackTrace(); } return false; } /** * 登录验证(全文件扫描) */ public boolean login(String username, String password) { String hashedPassword = hashPassword(password); try (BufferedReader br = new BufferedReader(new FileReader(FILE_PATH))) { String line; while ((line = br.readLine()) != null) { // O(n) 全表扫描 String[] parts = line.split(","); if (parts[0].equals(username) && parts[1].equals(hashedPassword)) { return true; } } } catch (IOException e) { e.printStackTrace(); } return false; } /** * 按注册时间范围查询(全文件扫描+过滤) */ public List<User> findByRegisteredDateRange(long startTime, long endTime) { List<User> result = new ArrayList<>(); try (BufferedReader br = new BufferedReader(new FileReader(FILE_PATH))) { String line; while ((line = br.readLine()) != null) { // O(n) 全表扫描 String[] parts = line.split(","); long registeredTime = Long.parseLong(parts[2]); if (registeredTime >= startTime && registeredTime <= endTime) { result.add(new User(parts[0], parts[1], registeredTime)); } } } catch (IOException e) { e.printStackTrace(); } return result; } private String hashPassword(String password) { // 简化版,实际应该用BCrypt return Integer.toString(password.hashCode()); } } 文件内容示例: ...

2025-11-03 · maneng

MySQL索引原理:从O(n)到O(log n)的飞跃

引言 “计算机科学领域的任何问题都可以通过增加一个间接的中间层来解决。” —— David Wheeler 在上一篇文章《MySQL第一性原理:为什么我们需要数据库?》中,我们了解到MySQL通过索引将查询性能从O(n)提升到O(log n),实现了10万倍的性能飞跃。 但你有没有想过: 为什么索引能这么快? 从1亿条数据中查找一条,只需要3-4次磁盘IO 为什么MySQL选择B+树? 而不是哈希表、二叉搜索树、红黑树? 为什么有些查询用不上索引? WHERE id + 1 = 100 vs WHERE id = 99 联合索引的最左前缀原则是什么? 为什么(user_id, created_time)索引无法优化WHERE created_time > xxx? 今天,我们从第一性原理出发,通过对比5种数据结构,深度剖析MySQL索引的演进历程: 顺序扫描 → 哈希索引 → 二叉搜索树 → B树 → B+树 O(n) O(1) O(log₂n) O(logₘn) O(logₘn) + 顺序IO 1秒 ? ? ? 10微秒 我们还将手写300行代码,实现一个简化版B+树,彻底理解索引的实现原理。 一、问题的起点:全表扫描的性能瓶颈 让我们从一个最简单的查询开始: -- 用户表,1亿条数据 SELECT * FROM users WHERE id = 50000000; 如果没有索引,MySQL会怎么做? 1.1 顺序扫描(Full Table Scan) 执行过程: 1. 从磁盘读取第1页数据(16KB,约100行)→ 判断id是否等于50000000 → 不是 2. 从磁盘读取第2页数据 → 判断 → 不是 3. 从磁盘读取第3页数据 → 判断 → 不是 ... 500000. 从磁盘读取第50万页数据 → 判断 → 是! ✅ 总计:扫描50万页,约8GB数据 性能分析: ...

2025-11-03 · maneng

MySQL索引原理:从O(n)到O(log n)的飞跃

引言 “计算机科学领域的任何问题都可以通过增加一个间接的中间层来解决。” —— David Wheeler 在上一篇文章《MySQL第一性原理:为什么我们需要数据库?》中,我们了解到MySQL通过索引将查询性能从O(n)提升到O(log n),实现了10万倍的性能飞跃。 但你有没有想过: 为什么索引能这么快? 从1亿条数据中查找一条,只需要3-4次磁盘IO 为什么MySQL选择B+树? 而不是哈希表、二叉搜索树、红黑树? 为什么有些查询用不上索引? WHERE id + 1 = 100 vs WHERE id = 99 联合索引的最左前缀原则是什么? 为什么(user_id, created_time)索引无法优化WHERE created_time > xxx? 今天,我们从第一性原理出发,通过对比5种数据结构,深度剖析MySQL索引的演进历程: 顺序扫描 → 哈希索引 → 二叉搜索树 → B树 → B+树 O(n) O(1) O(log₂n) O(logₘn) O(logₘn) + 顺序IO 1秒 ? ? ? 10微秒 我们还将手写300行代码,实现一个简化版B+树,彻底理解索引的实现原理。 一、问题的起点:全表扫描的性能瓶颈 让我们从一个最简单的查询开始: -- 用户表,1亿条数据 SELECT * FROM users WHERE id = 50000000; 如果没有索引,MySQL会怎么做? 1.1 顺序扫描(Full Table Scan) 执行过程: 1. 从磁盘读取第1页数据(16KB,约100行)→ 判断id是否等于50000000 → 不是 2. 从磁盘读取第2页数据 → 判断 → 不是 3. 从磁盘读取第3页数据 → 判断 → 不是 ... 500000. 从磁盘读取第50万页数据 → 判断 → 是! ✅ 总计:扫描50万页,约8GB数据 性能分析: ...

2025-11-03 · maneng

MySQL事务与锁:并发控制的艺术

引言 “并发是计算机科学中最难的问题之一,因为它涉及时间、顺序和不确定性。” —— Leslie Lamport 在前两篇文章中,我们了解了MySQL如何通过索引实现快速查询,如何通过WAL日志保证数据持久化。但还有一个核心问题没有解决: 如何在高并发场景下保证数据一致性? 想象这样的场景: 双11零点,100万用户同时抢购一件库存只有10个的商品 每个用户都执行: 1. 读取库存 → 10 2. 判断库存足够 → 是 3. 扣减库存 → 库存 - 1 4. 创建订单 结果:卖出了100万件,但库存只扣了10个 💥 这就是并发控制的核心难题:如何让多个并发事务互不干扰,同时保证数据一致性? 今天,我们从第一性原理出发,深度剖析MySQL的并发控制机制: 无控制 → 锁机制 → MVCC → 隔离级别 → 死锁处理 混乱 串行化 读写分离 灵活平衡 自动恢复 ❌ ⚠️ ✅ ✅ ✅ 我们还将手写MVCC核心逻辑,彻底理解MySQL如何实现读写不阻塞。 一、问题的起点:并发导致的数据混乱 让我们从一个最经典的并发问题开始:电商库存扣减。 1.1 场景:秒杀商品超卖问题 需求: 商品:iPhone 16 Pro Max(库存10件) 活动:双11零点秒杀,原价9999元,秒杀价1元 预期:10个用户抢到,其余用户提示"已抢完" 无并发控制的实现: /** * 秒杀服务(无并发控制) */ @Service public class SeckillService { @Autowired private ProductMapper productMapper; @Autowired private OrderMapper orderMapper; /** * 秒杀下单(存在并发问题) */ public boolean seckill(Long productId, Long userId) { // 1. 读取库存 Product product = productMapper.selectById(productId); int stock = product.getStock(); // 2. 判断库存是否足够 if (stock <= 0) { return false; // 库存不足 } // 3. 扣减库存 product.setStock(stock - 1); productMapper.updateById(product); // 4. 创建订单 Order order = new Order(); order.setUserId(userId); order.setProductId(productId); order.setAmount(1.00); // 秒杀价1元 orderMapper.insert(order); return true; } } 并发测试: ...

2025-11-03 · maneng

MySQL事务与锁:并发控制的艺术

引言 “并发是计算机科学中最难的问题之一,因为它涉及时间、顺序和不确定性。” —— Leslie Lamport 在前两篇文章中,我们了解了MySQL如何通过索引实现快速查询,如何通过WAL日志保证数据持久化。但还有一个核心问题没有解决: 如何在高并发场景下保证数据一致性? 想象这样的场景: 双11零点,100万用户同时抢购一件库存只有10个的商品 每个用户都执行: 1. 读取库存 → 10 2. 判断库存足够 → 是 3. 扣减库存 → 库存 - 1 4. 创建订单 结果:卖出了100万件,但库存只扣了10个 💥 这就是并发控制的核心难题:如何让多个并发事务互不干扰,同时保证数据一致性? 今天,我们从第一性原理出发,深度剖析MySQL的并发控制机制: 无控制 → 锁机制 → MVCC → 隔离级别 → 死锁处理 混乱 串行化 读写分离 灵活平衡 自动恢复 ❌ ⚠️ ✅ ✅ ✅ 我们还将手写MVCC核心逻辑,彻底理解MySQL如何实现读写不阻塞。 一、问题的起点:并发导致的数据混乱 让我们从一个最经典的并发问题开始:电商库存扣减。 1.1 场景:秒杀商品超卖问题 需求: 商品:iPhone 16 Pro Max(库存10件) 活动:双11零点秒杀,原价9999元,秒杀价1元 预期:10个用户抢到,其余用户提示"已抢完" 无并发控制的实现: /** * 秒杀服务(无并发控制) */ @Service public class SeckillService { @Autowired private ProductMapper productMapper; @Autowired private OrderMapper orderMapper; /** * 秒杀下单(存在并发问题) */ public boolean seckill(Long productId, Long userId) { // 1. 读取库存 Product product = productMapper.selectById(productId); int stock = product.getStock(); // 2. 判断库存是否足够 if (stock <= 0) { return false; // 库存不足 } // 3. 扣减库存 product.setStock(stock - 1); productMapper.updateById(product); // 4. 创建订单 Order order = new Order(); order.setUserId(userId); order.setProductId(productId); order.setAmount(1.00); // 秒杀价1元 orderMapper.insert(order); return true; } } 并发测试: ...

2025-11-03 · maneng

MySQL查询优化:从执行计划到性能调优

引言 “过早优化是万恶之源。但当性能问题真正出现时,优化就是救命稻草。” —— Donald Knuth 在前三篇文章中,我们学习了索引、事务、锁的原理。但光有理论还不够,如何定位和优化慢查询? 想象这样的场景: 凌晨3点,你被一通电话吵醒: "数据库快挂了,所有查询都超时!" 你打开监控,发现: - CPU 100% - 慢查询日志爆满 - 某个SQL执行了10秒还没返回 如何快速定位问题?如何优化这个慢查询? 这就是查询优化的核心价值:让慢查询变快,让系统起死回生。 今天,我们从第一性原理出发,深度剖析MySQL的查询优化: SQL执行流程: 客户端 → 连接器 → 解析器 → 优化器 → 执行器 → 存储引擎 ↓ ↓ ↓ ↓ ↓ 权限检查 语法解析 生成计划 执行查询 返回数据 性能优化: 慢查询 → EXPLAIN → 找到瓶颈 → 优化索引 → 改写SQL → 性能飞跃 10秒 分析 全表扫描 建索引 覆盖索引 10ms 我们还将通过10个真实案例,将慢查询从10秒优化到10ms,性能提升1000倍。 一、SQL执行流程:从SQL到结果集 理解查询优化,首先要理解SQL是如何执行的。 1.1 MySQL的架构:两层结构 ┌─────────────────────────────────────────────────────────────┐ │ MySQL Server层 │ ├─────────────────────────────────────────────────────────────┤ │ 连接器 解析器 优化器 执行器 │ │ ↓ ↓ ↓ ↓ │ │ 权限验证 语法解析 生成计划 执行查询 │ └─────────────────────────────────────────────────────────────┘ ↓ ┌─────────────────────────────────────────────────────────────┐ │ 存储引擎层 │ ├─────────────────────────────────────────────────────────────┤ │ InnoDB MyISAM Memory Archive │ │ ↓ ↓ ↓ ↓ │ │ 事务支持 不支持 内存存储 压缩存储 │ └─────────────────────────────────────────────────────────────┘ Server层与存储引擎的职责分工: ...

2025-11-03 · maneng

如约数科科技工作室

浙ICP备2025203501号

👀 本站总访问量 ...| 👤 访客数 ...| 📅 今日访问 ...