一、MySQL 概述

(一)MySQL 是什么
MySQL 是一种关系型数据库管理系统,它采用了 SQL(Structured Query Language,结构化查询语言)来管理和操作数据。MySQL 以表格的形式存储数据,每个表格由若干行和列组成,行代表记录,列代表字段。通过 SQL 语句,可以对这些表格中的数据进行查询、插入、更新和删除等操作。
MySQL 具有高度的可扩展性,可以在不同规模的应用中使用。它支持多种存储引擎,每种存储引擎都有其特定的优势和适用场景。例如,InnoDB 存储引擎提供了事务支持和行级锁定,适用于对数据完整性和并发性要求较高的应用;MyISAM 存储引擎则在查询性能方面表现出色,适用于以读为主的应用。
(二)应用场景广泛

MySQL 是一款极为重要的开源关系型数据库管理系统。它最初是由瑞典的一家公司开发而成。在数据库领域,MySQL 占据着重要的地位。后来,MySQL 被 Oracle 公司收购。MySQL 支持 SQL 语言,这使得用户可以通过 SQL 语句对数据库进行各种操作,如查询、插入、更新和删除数据等。SQL 语言的支持使得 MySQL 具有强大的功能和广泛的适用性,无论是小型项目还是大型企业级应用,都能很好地满足用户的需求。
(三)与其他数据库对比
MySQL 与 Oracle、Microsoft SQL Server、PostgreSQL 相比,具有独特的特点和优势。

与 Oracle 对比:Oracle 是一款商业数据库,需要支付较高的许可费用,而 MySQL 是开源的,可以免费使用。Oracle 在大型企业级应用上表现卓越,其复杂度、并发性和数据规模都比 MySQL 更高。但 MySQL 对于小型和中小型应用更加轻便灵活,成本更低。例如,对于一些个人站点、初创公司,考虑到成本和系统重要性等问题,MySQL 往往是更好的选择。
与 Microsoft SQL Server 对比:Microsoft SQL Server 在 Windows 平台上有较好的集成性和易用性。但 MySQL 跨平台性更好,支持各种硬件平台和操作系统。在性能方面,对于中小型应用,MySQL 的表现并不逊色。同时,MySQL 的社区非常活跃,用户可以轻松地找到丰富的第三方工具和资源。
与 PostgreSQL 对比:PostgreSQL 在功能和标准遵从性上更为强大,支持更多的数据类型和高级特性。然而,MySQL 在处理大规模读操作和简单查询时表现更为出色,并且具有更好的易用性。对于一些对性能要求不是特别高,但需要快速开发和部署的应用,MySQL 更具优势。
总的来说,MySQL 在开源、成本低、性能和可扩展性、易用性等方面具有显著优势,使其在不同规模的应用场景中都有广泛的应用。用户可以根据自己的具体需求和应用场景选择最适合自己的数据库管理系统。
二、安装与配置

(一)选择合适版本
MySQL 提供了多个版本供用户选择,其中 MySQL Community Server 是开源免费的社区版本,适合大多数个人用户和小型企业使用。对于有更高需求和预算的企业,可以考虑使用 MySQL Enterprise Server 等付费版本,这些版本通常提供了更全面的技术支持和高级功能。在选择版本时,用户应根据自己的操作系统、应用需求和预算来决定。
(二)安装步骤详解
对于 Windows 用户来说,安装 MySQL 可以按照以下步骤进行。首先,从 MySQL 官方网站下载适合自己操作系统的安装程序。在运行安装程序时,用户可以根据提示逐步进行操作,包括选择安装路径、配置服务器参数等。在配置路径时,建议选择一个易于记忆和访问的位置。安装过程中还可以选择需要安装的组件,如数据库服务器、客户端工具等。最后,创建一个密码来保护数据库的安全。安装完成后,可以通过 MySQL 自带的客户端工具或者命令行来连接数据库。
(三)配置环境变量
配置环境变量可以让用户在命令行中更方便地使用 MySQL。具体步骤如下:首先,找到 MySQL 的安装路径,通常在安装过程中可以自定义这个路径。然后,在系统变量中新建一个变量名为 “MYSQL_HOME” 的变量,变量值设置为 MySQL 的安装路径。接着,在系统变量的 “Path” 中添加 “% MYSQL_HOME%\bin”,这样就可以在命令行中直接使用 MySQL 的命令了。例如,输入 “mysql -u root -p” 可以登录数据库,输入密码后即可进入 MySQL 命令行界面。
(四)启动与停止服务
在 Windows 系统中,可以通过命令行或服务管理工具来启动和停止 MySQL 服务。通过命令行启动服务的方法是:以管理员身份运行 cmd,输入 “net start mysql” 即可启动 MySQL 服务;输入 “net stop mysql” 可以停止服务。另外,也可以在 “任务管理器” 的 “服务” 选项卡中找到 MySQL 服务,进行启动和停止操作。在其他操作系统中,如 Linux 和 macOS,也有相应的命令和工具来管理 MySQL 服务。例如,在 Linux 系统中,可以使用 “service mysql start” 和 “service mysql stop” 来启动和停止 MySQL 服务。
三、基础操作

(一)数据库创建与管理
数据库是存放多个表的容器,在 MySQL 中,我们使用CREATE DATABASE命令来创建数据库。其语法为:CREATE DATABASE 数据库名。例如,要创建一个名为my_database的数据库,可以使用命令:CREATE DATABASE my_database。执行这个命令后,MySQL 会在服务器上创建一个新的数据库,名为my_database。创建数据库后,可以使用SHOW DATABASES命令查看已创建的数据库列表,以确认数据库是否创建成功。如果要删除数据库,可以使用DROP DATABASE命令,例如DROP DATABASE my_database,但需注意执行此命令将永久删除该数据库以及其中的所有数据,所以在执行前要确保已备份重要数据。

(二)表设计与创建
表是存储特定类型数据的基本单元。创建表的语法为:CREATE TABLE <表名>(<字段名称><数据类型>,<字段名称><数据类型>,<字段名称><数据类型>,......)。例如,给定一个学员信息表,建表 SQL 语句如下:CREATE TABLE stuInfo(stuid int unsigned primary key,stuname varchar(10) not null,gender varchar(5),birthdate date,age int(3),city varchar(20))。其中primary key表示主键,作为记录的唯一标识。
(三)数据插入与查询
数据插入:向表中插入数据通过insert into进行,语法格式为:insert into <表名>(字段 1,字段 2,......) values(字段 1 的值,字段 2 的值,......)。例如,向表stuinfo插入一条记录,SQL 语句为:insert into stuinfo(stuid,stuname,gender,birthdate,age,city)values(20161001,'Sunbin','男','1990/1/1',28,'Beijing')。如果需要一次性插入多条记录,格式为:insert into <表名>(字段 1,字段 2,......) values(字段 1 的值,字段 2 的值,......),(字段 1 的值,字段 2 的值,......),(字段 1 的值,字段 2 的值,......)。
数据查询:查询数据通过select子句进行。例如,想查询表stuinfo中的所有记录,SQL 语句为:select * from stuinfo。如果想查询符合某个条件的记录,就要用到where子句了,SQL 格式为:select * from <表名> where 字段名=某个值。例如,想查询stuid为 20161001 的记录,SQL 语句为:select * from stuinfo where stuid=20161001。
(四)SQL 语句使用
MySQL 提供了各种 SQL 语句,如:
INSERT:用于向表中插入新数据。
UPDATE:更新数据库表中的数据。语法为:UPDATE <表名> SET 字段名=新值 WHERE 条件。例如,更新stuinfo表中stuid为 20161001 的记录的stuname字段为 'NewName',SQL 语句为:UPDATE stuinfo SET stuname='NewName' WHERE stuid=20161001。
DELETE:从数据库表中删除数据。语法为:DELETE FROM <表名> WHERE 条件。例如,删除stuinfo表中stuid为 20161002 的记录,SQL 语句为:DELETE FROM stuinfo WHERE stuid=20161002。
SELECT:从数据库表中获取数据。可以结合FROM、WHERE、GROUP BY、HAVING、ORDER BY、LIMIT等子句实现复杂的查询功能。例如,SELECT id, name FROM users WHERE id>10 ORDER BY name ASC LIMIT 5表示从users表中查询id大于 10 的记录的id和name字段,按照name字段升序排序,只返回前 5 条记录。
四、数据类型与 SQL 分类

(一)数据类型
数值类型:
MySQL 的数值类型主要包括整型、浮点型、精确数值型等。例如,TINYINT是 1 个字节的整型,取值范围为 -128~127,TINYINT UNSIGNED取值范围为 0~255。INT是 4 个字节的整型,取值范围为 -2147483648~2147483647,INT UNSIGNED取值范围为 0~4294967295。
浮点型有FLOAT和DOUBLE。FLOAT(M,D)单精度浮点数类型,占用 4 个字节。DOUBLE(M,D)双精度浮点数类型,占用 8 个字节。例如,FLOAT(6,2)表示该浮点数总长度为 6,小数点后保留 2 位。
DECIMAL(M,D)是精确数值类型,常用于金融货币等需要精确计算的场合。M 表示小数点前后总的位数,最大为 65,D 为小数点后的位数,最大为 30。
字符串类型:
CHAR与VARCHAR是最常用的字符串类型。CHAR是定长字符串,长度在创建表时就已确定,长度范围从 1 到 255 个字符。例如,CHAR(10)不管实际存储的数据长度如何,都会占用 10 个字符的空间,不足部分以空格填充,读取速度快。
VARCHAR是可变长度的字符串,与CHAR相比,节省空间,只占用必要的空间加上一个额外的字节来记录长度(如果列声明的长度超过 255,则需要两个字节)。例如,VARCHAR(65535)最大长度可以达到 65,535 个字符,但实际限制取决于行大小和字符集。
TEXT类型用于存储大量文本数据,根据存储需求的不同,分为TINYTEXT、TEXT、MEDIUMTEXT和LONGTEXT。TEXT列不存储在数据库行内,而是作为大型对象存储在外部,只在行内保留一个指针。
BLOB类型与TEXT类型相似,但用于存储大型的二进制数据,如图片、音频和视频等。同样存储在外部,并通过行内指针进行访问。根据存储需求的不同,分为TINYBLOB、BLOB、MEDIUMBLOB和LONGBLOB。
日期类型:
DATE只包含年月日,例如存储生日等信息。
DATETIME是混合日期和时间值,包含年月日时分秒。
TIMESTAMP表示时间戳,存储当前时间到 1970 年 1 月 1 日 0 时 0 分 0 秒经过的秒数。
(二)SQL 分类

DDL(数据定义语言):
用于定义和管理数据库的结构。主要操作包括创建、修改和删除数据库对象,如表、索引等。
例如,CREATE DATABASE用于创建数据库,CREATE TABLE用于创建表,ALTER TABLE用于修改表结构,DROP TABLE用于删除表。
DML(数据操作语言):
用于对数据库中的数据进行操作,包括插入、查询、更新和删除数据。
例如,INSERT INTO用于向表中插入新数据,SELECT用于从数据库表中获取数据,UPDATE用于更新数据库表中的数据,DELETE FROM用于从数据库表中删除数据。
DQL(数据查询语言):
用于查询数据库中表的记录。
可以结合FROM、WHERE、GROUP BY、HAVING、ORDER BY、LIMIT等子句实现复杂的查询功能。例如,SELECT id, name FROM users WHERE id>10 ORDER BY name ASC LIMIT 5表示从users表中查询id大于 10 的记录的id和name字段,按照name字段升序排序,只返回前 5 条记录。
DCL(数据控制语言):
用于定义数据库的访问权限和安全级别,及创建用户。
例如,GRANT用于授予用户权限,REVOKE用于撤销用户权限。
五、安全与权限管理

(一)用户账号创建
在 MySQL 中创建用户有多种方式。可以使用 CREATE USER 语句,例如 CREATE USER 'new_user'@'localhost' IDENTIFIED BY 'password'; 创建一个名为 new_user 的用户,密码为 password,主机名为 localhost。也可以通过 INSERT INTO 语句将用户信息添加到 mysql.user 表中,但需要拥有对该表的 INSERT 权限。另外,还可以使用 GRANT 语句创建用户,例如 GRANT SELECT ON mydb.* TO 'new_user'@'localhost' IDENTIFIED BY 'password';,在创建用户的同时为其分配权限。
(二)权限分配与控制
GRANT 命令用于管理访问权限,给用户账号授权。例如 GRANT ALL PRIVILEGES ON *.* TO 'admin'@'localhost'; 授予用户 admin 在本地主机对所有数据库的所有权限。权限可以是 SELECT、INSERT、UPDATE、DELETE 等具体操作权限,也可以作用在不同层次上,如整个 MySQL 服务器(GRANT SELECT ON *.* TO 'dba'@'localhost';)、单个数据库(GRANT SELECT ON testdb.* TO 'dba'@'localhost';)、单个数据表(GRANT SELECT, INSERT, UPDATE, DELETE ON testdb.orders TO 'dba'@'localhost';)、表中的列(GRANT SELECT(id, se, rank) ON testdb.apache_log TO 'dba'@'localhost';)、存储过程和函数(GRANT EXECUTE ON PROCEDURE testdb.pr_add TO 'dba'@'localhost'; GRANT EXECUTE ON FUNCTION testdb.fn_add TO 'dba'@'localhost';)。
REVOKE 命令用于撤销已经赋予给 MySQL 用户权限的权限,语法与 GRANT 类似,只需要把关键字 “to” 换成 “from” 即可,例如 REVOKE ALL ON *.* FROM 'dba'@'localhost';。
SHOW GRANTS 命令可以查看用户权限信息,例如 SHOW GRANTS FOR 'user'@'host';。
(三)安全策略
强密码策略:数据库的密码策略需要设置成最少 8 位由数字、大写字母、小写字母、特殊字符三种组成,密码需要 90 天强制更换密码,更换的密码与上一次不能一致。需有登录失败策略,登录失败 5 次锁定账户 3 分钟,需有登录连接超时策略,登录连接超时 30 分钟自动退出。要实现如上策略需要借助 validate_password_policy 插件,安装插件 INSTALL PLUGIN validate_password SONAME 'validate_password.so';,查看插件 show global variables like '%validate_password%';,查看插件安装位置 show variables like 'plugin_dir';。参数 validate-password=ON/OFF/FORCE/FORCE_PLUS_PERMANENT 决定是否使用该插件(及强制 / 永久强制使用)。validate_password_dictionary_file 是插件用于验证密码强度的字典文件路径。validate_password_length 是密码最小长度,默认值为 8,它有最小值的限制,最小值为:validate_password_number_count + validate_password_special_char_count + (2 * validate_password_mixed_case_count)。validate_password_mixed_case_count 是密码至少要包含的小写字母个数和大写字母个数。validate_password_number_count 是密码至少要包含的数字个数。validate_password_policy 是密码强度检查等级,有 0/LOW、1/MEDIUM、2/STRONG 三个等级。0/LOW 只检查长度;1/MEDIUM 检查长度、数字、大小写、特殊字符;2/STRONG 检查长度、数字、大小写、特殊字符字典文件。增强密码强度可设置 SET GLOBAL validate_password_policy=STRONG;。查看密码生命周期 show global variables like '%default_password_lifetime%';,设置密码生命周期 SET GLOBAL default_password_lifetime=90;。查看登录失败次数 show global variables like '%max_connect_errors%';,设置登录失败次数 set global max_connect_errors=5;。查看账号锁定时间 show global variables like '%connect_timeout%';,设置账号锁定时间 SET GLOBAL connect_timeout=300;。查看超时自动退出时间 show global variables like '%wait_timeout%';,设置超时自动退出时间 SET GLOBAL wait_timeout=1800;。
最小权限原则:业务帐号权限最小化,坚决不允许 DROP、TRUNCATE 权限。业务账号默认只授予普通的 DML 所需权限,也就是 select、update、insert、delete、execute 等几个权限,其余不给。
定期审计:可以采用 Percona 的 SQL 审计插件,对数据库操作进行审计,确保数据安全。
数据加密:应用程序中涉及账号密码的地方例如 JDBC 连接串配置,尽量把明文密码采用加密方式存储,再利用内部私有的解密工具进行反解密后再使用。或者可以让应用程序先用中间账号连接 proxy 层,再由 proxy 连接 MySQL,避免应用层直连 MySQL。
六、优化与性能调优

(一)索引优化
索引在数据库中起着至关重要的作用。它可以大大加快数据的检索速度,保证数据库表中每一行数据的唯一性,加速表和表之间的连接,减少查询中分组和排序的时间,提高系统的性能。
创建方法:
普通索引:可以通过多种方式创建,如直接创建索引CREATE INDEX index_name ON table(column(length));修改表结构的方式添加索引ALTER TABLE table_name ADD INDEX index_name ON (column(length));创建表的时候直接指定CREATE TABLE mytable( ID INT NOT NULL, username VARCHAR(16) NOT NULL, INDEX indexName (username(length)) );。
唯一索引:创建唯一索引CREATE UNIQUE INDEX indexName ON table(column(length));修改表结构ALTER TABLE table_name ADD UNIQUE indexName ON (column(length));创建表的时候直接指定Create TABLE tableName ( [...], UNIQUE [indexName](tableColumns(length));。
主键索引:一般是在建表的时候同时创建主键索引CREATE TABLE mytable( ID INT NOT NULL, username VARCHAR(16) NOT NULL, PRIMARY KEY(ID) );。
组合索引:使用ALTER TABLE table ADD INDEX name_city_age (name,city,age);,只有在查询条件中使用了创建索引时的第一个字段,索引才会被使用,遵循最左前缀集合。
全文索引:可以在create table,alter table,create index使用,如CREATE TABLE table (id int(11) NOT NULL AUTO_INCREMENT,title char(255) CHARACTER NOT NULL,content text CHARACTER NULL,time int(10) NULL DEFAULT NULL,PRIMARY KEY (id),FULLTEXT (content));。
使用注意事项:
索引不会包含有NULL值的列,只要列中包含有NULL值都将不会被包含在索引中。
使用短索引,对串列进行索引时,如果可能应该指定一个前缀长度,例如,如果有一个CHAR(255)的列,如果在前 10 个或 20 个字符内,多数值是惟一的,那么就不要对整个列进行索引。
索引列排序时,如果where子句中已经使用了索引,那么order by中的列是不会使用索引的。
like语句操作中,like “�a%”不会使用索引,而like “aaa%”可以使用索引。
不要在列上进行运算,如select * from users where YEAR(adddate)<2007;将在每个行上进行运算,这将导致索引失效而进行全表扫描,应改成select * from users where adddate<‘2007-01-01’;。
不使用NOT IN和<>操作。
(二)查询优化
为了避免全表扫描,可以采取以下措施:
使用索引:在经常出现在WHERE子句中的列、ORDER BY子句中的列以及JOIN操作中的列创建索引。例如,假设有一个users表,包含id, name, email, age等字段。如果经常按照age进行查询,那么为age字段创建一个索引是有意义的。CREATE INDEX idx_age ON users(age);。
使用复合索引:当查询条件同时涉及多个列时,复合索引可以显著提高查询性能。如,如果经常同时按照age和name进行查询,可以创建一个复合索引。CREATE INDEX idx_age_name ON users(age, name);。注意复合索引的列顺序很重要,最常用作筛选条件的列应该放在前面。
使用覆盖索引:一个查询只需要通过索引就能获取所需数据,而无需回表查询原始数据。这可以显著提高查询性能。例如,如果经常查询用户的name和email,可以创建一个包含这两列的复合索引。CREATE INDEX idx_name_email ON users(name, email);当执行如下查询时,由于所需数据都在索引中,因此无需回表查询。SELECT name, email FROM users WHERE name = 'John Doe';。
优化索引长度:对于VARCHAR、BLOB或TEXT类型的列,可以指定索引的前缀长度来减少索引的大小和提高查询效率。但需要注意的是,这可能会影响到索引的选择性和查询性能。例如,为name字段的前 10 个字符创建索引。CREATE INDEX idx_name_prefix ON users(name(10));。
使用EXPLAIN分析查询执行计划可以帮助我们了解MySQL如何执行查询。它显示MySQL将如何访问表以及使用哪些索引。通过使用EXPLAIN命令,您可以识别并优化慢查询,找出问题所在并进行优化。例如:EXPLAIN select * from payment;查询结果中有 12 列,理解每一列的含义,对理解执行计划至关重要。
(三)事务与并发控制

事务具有四个属性ACID:
Atomicity(原子性):事务是一个不可分割的工作单位,事务的所有操作要么全部完成,要么全部不完成,不会只执行其中的一部分。
Consistency(一致性):事务必须是使数据库从一种状态变成另一种状态的方式必须是允许的。例如,事务不能破坏关系数据的完整性、参照完整性和触发器。
Isolation(隔离性):一个事务的执行不能被其他事务干扰。换句话说,一个事务内部的操作及使用的数据对并发的其他事务是隔离的,并发执行的各个事务之间不能互相干扰。
Durability(持久性):一旦事务提交,它对数据库的改变就应该是永久性的。即使系统发生故障,也不应该丢失已提交事务的修改。
在MySQL中,并发控制主要是通过锁机制来实现的。主要有读锁(也叫共享锁)和写锁(也叫排他锁)。读锁允许多个读请求同时共享一把锁来读取数据,而不会造成阻塞;写锁会排斥其他所有获取锁的请求,一直阻塞,直到完成写入并释放锁。
MySQL的锁粒度主要有表锁和行锁。表锁会锁定整张表,维护锁的开销最小,但会降低表的读写效率;行锁可以最大程度地支持并发读写,但数据库维护锁的开销会比较大。行锁一般由具体的存储引擎实现。
MySQL还通过MVCC(多版本并发控制)来实现读写分离,从而实现不加锁读取数据进而做到了读写并行。InnoDB的MVCC,是通过在每行记录后面保存两个隐藏的列来实现的。这两个列,一个保存了行的创建时间,一个保存了行的过期时间。当然它们存储的并不是实际的时间值,而是系统版本号。每开启一个新的事务,系统版本号都会自动递增;事务开始时刻的系统版本号会作为事务的版本号,用来和查询到的每行记录的版本号进行比较。
七、实战演练

(一)设计数据库模式
对于管理博客的数据库,我们可以设计以下三个主要的表:用户表(users)、文章表(articles)和评论表(comments)。
用户表(users):
CREATE TABLE users ( user_id INT AUTO_INCREMENT PRIMARY KEY, username VARCHAR(50) NOT NULL, email VARCHAR(100) UNIQUE NOT NULL, password VARCHAR(255) NOT NULL ); |
用户表用于存储博客用户的信息,包括用户 ID、用户名、邮箱和密码。
文章表(articles):
CREATE TABLE articles ( article_id INT AUTO_INCREMENT PRIMARY KEY, user_id INT, title VARCHAR(255) NOT NULL, content TEXT NOT NULL, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, FOREIGN KEY (user_id) REFERENCES users(user_id) ); |
文章表存储博客文章的信息,有文章 ID、作者用户 ID、标题、内容和创建时间,通过外键关联到用户表。
评论表(comments):
CREATE TABLE comments ( comment_id INT AUTO_INCREMENT PRIMARY KEY, article_id INT, user_id INT, content TEXT NOT NULL, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, FOREIGN KEY (article_id) REFERENCES articles(article_id), FOREIGN KEY (user_id) REFERENCES users(user_id) ); |
评论表用于存储用户对文章的评论,包括评论 ID、文章 ID、评论用户 ID、评论内容和创建时间,通过外键关联到文章表和用户表。
(二)完成数据录入与查询
数据插入:
向用户表插入数据:
INSERT INTO users (username, email, password) VALUES ('user1', 'user1@example.com', 'password1'); INSERT INTO users (username, email, password) VALUES ('user2', 'user2@example.com', 'password2'); |
向文章表插入数据:
INSERT INTO articles (user_id, title, content) VALUES (1, 'Article 1', 'This is the content of article 1.'); INSERT INTO articles (user_id, title, content) VALUES (2, 'Article 2', 'This is the content of article 2.'); |
向评论表插入数据:
INSERT INTO comments (article_id, user_id, content) VALUES (1, 2, 'This is a comment on article 1.'); INSERT INTO comments (article_id, user_id, content) VALUES (2, 1, 'This is a comment on article 2.'); |
数据查询:
查询所有文章及其作者信息:
SELECT a.article_id, a.title, a.content, u.username FROM articles a JOIN users u ON a.user_id = u.user_id; |
查询某篇文章的所有评论:
SELECT c.comment_id, c.content, u.username FROM comments c JOIN users u ON c.user_id = u.user_id WHERE c.article_id = 1; |
(三)应用部署与测试
假设我们有一个使用某种编程语言(如 Python 的 Flask 框架)开发的博客应用。首先,我们需要连接 MySQL 数据库。以下是一个使用 Python 和 SQLAlchemy 库连接 MySQL 的示例代码:
from flask import Flask from flask_sqlalchemy import SQLAlchemy app = Flask(__name__) app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql://username:password@localhost/blog_db' db = SQLAlchemy(app) |
在应用中,我们可以定义模型类来对应数据库中的表:
class User(db.Model): user_id = db.Column(db.Integer, primary_key=True) username = db.Column(db.String(50), nullable=False) email = db.Column(db.String(100), unique=True, nullable=False) password = db.Column(db.String(255), nullable=False) class Article(db.Model): article_id = db.Column(db.Integer, primary_key=True) user_id = db.Column(db.Integer, db.ForeignKey('user.user_id'), nullable=False) title = db.Column(db.String(255), nullable=False) content = db.Column(db.Text, nullable=False) created_at = db.Column(db.Timestamp, default=db.func.current_timestamp()) class Comment(db.Model): comment_id = db.Column(db.Integer, primary_key=True) article_id = db.Column(db.Integer, db.ForeignKey('article.article_id'), nullable=False) user_id = db.Column(db.Integer, db.ForeignKey('user.user_id'), nullable=False) content = db.Column(db.Text, nullable=False) created_at = db.Column(db.Timestamp, default=db.func.current_timestamp()) |
为了确保数据正确性和应用稳定性,我们可以编写测试用例。例如,测试插入数据后能否正确查询到数据:
def test_data_insertion_and_query(): user1 = User(username='user1', email='user1@example.com', password='password1') user2 = User(username='user2', email='user2@example.com', password='password2') db.session.add(user1) db.session.add(user2) db.session.commit() article1 = Article(user_id=1, title='Article 1', content='This is the content of article 1.') article2 = Article(user_id=2, title='Article 2', content='This is the content of article 2.') db.session.add(article1) db.session.add(article2) db.session.commit() comment1 = Comment(article_id=1, user_id=2, content='This is a comment on article 1.') comment2 = Comment(article_id=2, user_id=1, content='This is a comment on article 2.') db.session.add(comment1) db.session.add(comment2) db.session.commit() articles_with_users = db.session.query(Article.article_id, Article.title, Article.content, User.username).join(User).all() assert len(articles_with_users) == 2 comments_on_article1 = db.session.query(Comment.comment_id, Comment.content, User.username).join(User).filter(Comment.article_id == 1).all() assert len(comments_on_article1) == 1 |
通过这样的实战演练,我们可以更好地理解和掌握 MySQL 的基础篇知识,包括数据库设计、数据录入与查询以及应用部署与测试。





