日拱一卒无有尽,功不唐捐终入海

MySQL的安装与使用

前言

不是所有的网站都需要数据库,但是如果一个网站需要以结构化的方式存储数据,并且网站的功能构建在这些数据上,会对这些数据产生增删改查的操作,那么这个网站需要数据库

1. 什么是数据库

数据库(Database)是按照数据结构来组织、存储和管理数据的仓库。它允许用户存储、检索和修改数据。数据库管理系统(Database Management System, DBMS)是用于与数据库交互的软件,它提供了数据的创建、查询、更新和管理的功能。

数据库的主要特点包括:

  • 数据持久性:数据存储在数据库中,即使系统关闭,数据也不会丢失。
  • 数据结构化:数据按照一定的结构组织,通常以表格的形式存储,每个表格由行(记录)和列(字段)组成。
  • 数据共享:多个用户或应用程序可以同时访问数据库中的数据。
  • 数据完整性:数据库管理系统确保数据的准确性和一致性。

2. 需要什么样的数据库

市面上可选择的数据库产品非常多,但是对于大多数情况来说,也许MySQL就够用了。MySQL是世界上最流行的开源数据库产品,最流行意味着使用最多(支持大多数应用场景)使用最多意味着很稳定,文档很丰富,也意味着坑比较少。即便有坑,也有人已经跳过了。

当然,如果你对数据库产品很熟悉,清楚的知道自己的业务场景需要哪些数据库去解决,那么选择自己熟悉的产品是最好的选择。

3. 什么是MySQL

MySQL是一个流行的开源关系型数据库管理系统(RDBMS),它使用结构化查询语言(SQL)进行数据库管理。MySQL最初由瑞典的MySQL AB公司开发,后来被Sun Microsystems收购,再后来Sun Microsystems被Oracle公司收购。尽管MySQL现在是Oracle的产品,但它仍然在开源社区中非常活跃,并且有一个由Oracle支持的开源版本,称为MySQL Community Edition(我们一般使用的MySQL是MySQL Community Edition)。

MySQL的特点包括:

  • 性能:MySQL以其高性能和可靠性而闻名,尤其是在处理大量数据时;
  • 灵活性与跨平台:它支持多种操作系统,如多种Unix和Linux变体、Windows和macOS,并且可以在多种硬件平台上运行;
  • 可扩展性:MySQL可以很好地扩展以满足不断增长的业务需求;
  • 安全性:提供了强大的数据加密和访问控制功能,以保护数据安全;
  • 成本效益:MySQL Community Edition是完全免费的,对于许多中小型企业来说,这是一个经济高效的选择;
  • 支持多种存储引擎:MySQL支持多种存储引擎,如InnoDB(默认存储引擎,支持事务处理、行级锁定和外键等)、MyISAM(不支持事务处理,但读写速度快)、Memory(将所有数据存储在内存中,提供快速访问)等;
  • 广泛的社区支持:由于其开源性质,MySQL拥有一个庞大的开发者社区,提供大量的文档、教程和论坛支持。

MySQL广泛应用于各种应用程序中,包括网站、企业资源规划(ERP)系统、内容管理系统(CMS)和许多其他类型的数据库驱动的应用程序。它也是许多流行的开源软件堆栈的组成部分,如LAMP(Linux、Apache、MySQL、PHP/Python/Perl)和MERN(MongoDB、Express.js、React、Node.js),尽管在MERN堆栈中通常使用MongoDB而不是MySQL。

4. 在Linux上安装MySQL

自从有了docker之后,MySQL的安装就变得简单许多(关于docker的安装与使用可以看这篇文章《Docker与Docker Compose的日常使用》)

4.1 确定镜像版本

MySQL镜像版本可以在docker的官方镜像网站中找到需要的镜像版本,我这里使用8.4.3。

4.2 拉取镜像

在服务器终端上输入:

docker pull mysql:8.4.3

或者,如果使用Docker Compose的话,也不需要单独拉取镜像:

services:
  mysql:
    image: mysql:8.4.3

因为Docker Compose启动容器的时候会先去本地查找是否有符合要求的镜像,如果有则直接使用,如果没有则去镜像站点拉取镜像。

4.3 定义YAML文件

services:
  mysql:
    image: mysql:8.4.3
    environment:
      MYSQL_ROOT_PASSWORD: your_root_password
    ports:
      - "5306:3306"
    volumes:
      - mysql_data:/var/lib/mysql
    restart: unless-stopped
    networks:
      - my_network

volumes:
  mysql_data:

networks:
  my_network:
    driver: bridge

在这个配置中:

  • services 下的 mysql 服务被连接到了 my_network 网络;
  • image 指定了使用的 MySQL 镜像和版本;
  • environment 部分设置了环境变量,你需要将 your_root_password替换为实际的密码;
  • ports 映射了容器的 3306 端口到宿主机的 5306 端口,这样你就可以通过宿主机的端口访问 MySQL 服务;
  • volumes 部分定义了一个持久化存储的卷 mysql_data,用于存储数据库文件,这样即使你删除了容器,数据也不会丢失;
  • restart 策略设置为 unless-stopped,这意味着容器将在退出时自动重启,除非它被明确停止。
  • networks 部分定义了一个名为 my_network 的网络。默认情况下,Docker Compose 使用 bridge 驱动创建网络,但你也可以选择其他驱动,如 overlay(用于跨多个宿主机的网络)

稍微详细解释一下:

4.3.1 MYSQL_ROOT_PASSWORD

environment中的MYSQL_ROOT_PASSWORD必须得定义。如果在 docker-compose.yml 文件中不定义 MYSQL_ROOT_PASSWORD 环境变量,MySQL 容器将不会启动,因为 MySQL 8 及以上版本要求必须设置 root 用户的密码。这是出于安全考虑,以确保数据库在启动时有一个预设的密码,防止未经授权的访问。

如果你尝试在没有设置 MYSQL_ROOT_PASSWORD 的情况下启动容器,你会遇到错误,如下所示:

ERROR 1045 (28000): Access denied for user 'root'@'localhost' (using password: NO)

这是因为 MySQL 容器在启动时期望通过环境变量 MYSQL_ROOT_PASSWORD 获取 root 用户的密码。如果没有提供这个密码,MySQL 服务器将不允许任何用户登录,因为它认为没有设置安全的访问凭证。

因此,为了成功启动 MySQL 容器并能够登录到数据库,你必须在 docker-compose.yml 文件中设置 MYSQL_ROOT_PASSWORD 环境变量。

4.3.2 volumes

在 Docker Compose 中,volumes 部分用于定义数据卷,它允许你将容器内的数据持久化存储,即使容器被删除,数据也不会丢失。数据卷可以被看作是容器和宿主机之间的桥梁,用于数据的持久化和共享。

对于这个配置:

volumes:
  - mysql_data:/var/lib/mysql
  1. mysql_data:这是数据卷的名称。在 Docker Compose 中,你可以通过这个名字引用这个数据卷。它是一个用户定义的标签,用于在 Docker Compose 文件中标识这个特定的数据卷。
  2. /var/lib/mysql:这是容器内的挂载点。这意味着数据卷 mysql_data 将被挂载到容器的 /var/lib/mysql 目录。在 MySQL 容器中,这是 MySQL 数据文件的默认存储位置。

当你运行 Docker Compose 并启动服务时,如果 mysql_data 数据卷尚不存在,Docker 将自动为你创建它,在Linux上默认的路径将会是:/var/lib/docker/volumes/docker-compose_mysql-data/。如果数据卷已经存在,Docker 将使用现有的数据卷,这意味着之前的数据会被保留。

或者,如果你想在定义服务时指定宿主机的路径,可以这样写:

volumes:
      - /path/on/host/mysql_data:/var/lib/mysql

在这个例子中,/path/on/host/mysql_data 是宿主机上的一个目录,它将被挂载到容器的 /var/lib/mysql 目录,用于存储 MySQL 数据文件。请确保将 /path/on/host/mysql_data 替换为你实际想要使用的宿主机目录路径。

4.3.3 restart: unless-stopped

在 Docker Compose 中,restart 策略用于定义容器在退出时如何以及何时重新启动。restart 策略对于确保服务的高可用性非常重要,特别是在生产环境中。restart 策略可以设置为以下几种:

  1. no:容器在退出时不会自动重启;
  2. always:无论退出状态如何,容器总是重新启动;
  3. on-failure:仅当容器以非零状态退出时(即发生故障时),容器才会重启;
  4. unless-stopped:容器总是重新启动,除非它被手动停止或者 Docker 本身被停止。

restart: unless-stopped 是一个非常实用的策略,它的工作原理如下:

  • 自动重启:如果容器由于任何原因(例如应用程序崩溃、配置错误、资源不足等)意外退出,Docker 将自动重启该容器;
  • 手动停止:如果容器正在运行,你可以通过 docker stop 或 docker-compose stop 命令手动停止它。使用这个命令后,容器不会自动重启,除非你明确地再次启动它;
  • Docker 停止:如果 Docker 本身被停止或重启,那么所有使用 unless-stopped 策略的容器都不会自动重启,直到 Docker 服务再次被启动。

这个策略非常适合大多数服务,因为它确保了服务的连续性,同时允许管理员在需要时手动控制容器的生命周期。例如,如果你在维护期间需要停止服务,你可以手动停止容器,而不用担心 Docker 会自动重启它。

4.3.4 networks

在 Docker Compose 中定义网络非常简单。你可以在 docker-compose.yml 文件的底部添加一个 networks 部分来创建一个网络,比如:

networks:
  my_network:
    driver: bridge

在service中使用使用网络也非常简单:

services:
  mysql:
    networks:
      - my_network

一旦你定义了网络,所有连接到 my_network 的服务都可以使用网络别名进行相互发现和通信。在这个例子中,如果你有另一个服务需要连接到 MySQL,你可以简单地将那个服务也添加到 my_network 网络中,并且能够通过 mysql 这个别名来访问 MySQL 服务。这个配置对于接下来我们要说的在其它的容器中访问mysql容器非常重要!

5. 启动MySQL

有了YAML文件后,通过Docker Compose启动MySQL非常简单。可以在YAML文件目录下直接执行:

docker-compose up -d

或者

docker-compose -f mymysql.yml up -d

6. 初始化数据库

以上步骤创建了一个空的MySQL数据库。要使用它存储数据,就得创建数据库(Schema)、数据表(Table)与用户(user),并配置好对应的权限。

6.1 Schema

数据表(Table)与用户(user)好理解,数据库(Schema)不好理解,这里稍微解释一下。

Schema 在 MySQL 中通常被翻译为 模式 或者 架构。它代表数据库的逻辑结构,定义了数据库中所有对象的集合,包括:

  • :存储数据的基本单位,包含行和列。
  • 视图:基于表或其他视图的虚拟表,提供了一种看数据的不同方式。
  • 索引:用于加速数据检索的数据结构。
  • 存储过程:一组预编译的 SQL 语句,存储在数据库中,可重复执行。
  • 触发器:与表关联的数据库对象,在表发生某些操作(如插入、更新、删除)时自动执行。

形象地说,Schema 就是数据库的蓝图或模板。 它规定了数据库中有哪些表,这些表有哪些字段,字段的数据类型是什么,以及表与表之间的关系。

6.1.1 Schema 和 Database 的关系
  • MySQL中,Schema 和 Database 通常是一一对应的。 也就是说,一个数据库就是一个 Schema,反之亦然。
  • 其他数据库系统中,Schema 和 Database 可能有不同的概念。 例如,在 Oracle 数据库中,一个数据库可以包含多个 Schema。
6.1.2 Schema 的作用
  • 组织数据: 将相关的表、视图等对象组织在一起,便于管理。
  • 控制访问权限: 可以为不同的 Schema 设置不同的访问权限,实现数据隔离。
  • 模块化设计: 将数据库划分为不同的 Schema,可以提高数据库的设计和维护效率。

6.2 初始化

前言 在大多数情况下,随着网站或者系统的迭代开发,一个MySQL实例可能会有包含多个数据库(只要这个MySQL实例的性能不受影响),那么初始化数据库实际上是个需要多次进行的过程。

初始化数据库有很多种方式,但本质上还是准备好你的SQL脚本,里面有Schema、Table、Index、User、Privilege的定义,还有需要初始化导入的数据,即insert语句。这里我介绍一下我最常用的步骤。

6.2.1 在开发环境中准备好SQL脚本

在开发环境中操作数据库是最方便的,那就按照MySQL的要求创建好Schema、Table、Index、User,配置好Privilege,记下或者导出相应的SQL文件,比如叫init-20241022.sql。

如果有需要初始化导入的数据,一样在开发环境中处理好,导出到SQL文件中。

6.2.2 把SQL脚本上传到服务器上

通过scp或者之类的命令、工具上传文件,如果文件太大,可以先做个压缩,文本文件的压缩率是很可观的,可以省去不少空间。

6.2.3 在服务器上手动连接MySQL容器

首先找到容器的 ID 或名称:使用 docker ps 命令来查看所有正在运行的容器及其信息。你需要找到你的 MySQL 容器的 ID 或名称:

docker ps

其次找到容器在宿主机所在网络环境下的ip:

docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' [CONTAINER_ID_OR_NAME]

通过MySQL Client连接MySQL容器:

mysql -h <容器IP> -P <MySQL端口> -u root -p

按提示输入正确的root密码。当然你也可以用其它有权限的用户,而不仅仅是MySQL的root用户。

如果你的宿主机上没有MySQL Client,在Amazon Linux 2023Alibaba Cloud Linux3上,你也可以用如下命令进行安装:

sudo yum install mysql-client

其它发型版本的Linux可自行搜索安装方法。

最后,在成功进入MySQL Client命令行后,使用source命令执行初始化SQL文件

mysql> source ~/data/init-20241022.sql;

~/data/init-20241022.sql是你上传的初始化文件的位置,确保你的当前用户有权限访问它。

  • ~: 表示用户的主目录。例如,如果你的用户名是 “user1″,那么 “~” 就代表 “/home/user1″;
  • data: 在用户的主目录下有一个名为 “data” 的子目录;
  • init-20241022.sql: 在 “data” 目录下有一个名为 “init-20241022.sql” 的 SQL 脚本文件。
6.2.4 另一个执行初始化SQL文件的办法

首先,将 SQL 脚本复制到容器中

docker cp ~/data/init-20241022.sql [容器ID或名称]:/tmp/init-20241022.sql

然后,使用 docker exec 命令在容器内执行 SQL 脚本

docker exec -i [容器ID或名称] mysql -uroot -p[你的root密码] [数据库名称] < /tmp/init-20241022.sql

这样做的目的是确保MySQL容器有访问初始化SQL脚本的权限。

7. 连接数据库

MySQL实例(容器)已经启动了,数据库也初始化了,那么接下来就是要在应用程序中连接数据库并使用它了。在这里我以基于Python开发的Fastapi服务为例。

假设我已经把这个服务打包成my-fastapi:latest镜像,那么它的Docker Compose配置文件会是这样的:

services:
  my-fastapi:
    image: my-fastapi:latest
    ports:
      - "9000:8000"
    depends_on:
      - mysql
    environment:
      - DATABASE_URL=mysql://user:password@mysql:3306/db_name

networks:
  default:
    external:
      name: my_network

下面是每个部分的详细解释:

7.1 services: my-fastapi

  • image: my-fastapi:latest:这行指定了服务使用的 Docker 镜像。这里使用的是本地镜像 my-fastapi 的最新版本(latest 标签)。
  • ports:
    • - "9000:8000":这行设置了端口映射。它将容器内部的端口 8000 映射到宿主机的端口 9000。这意味着,当你访问宿主机的 9000 端口时,实际上是访问容器内部的 8000 端口。
  • depends_on:
    • - mysql:这行指定了 my-fastapi 服务的依赖。depends_on 确保在 my-fastapi 服务启动之前,mysql 服务已经启动。这有助于保证数据库服务在 FastAPI 应用启动前已经准备好。
  • environment:
    • DATABASE_URL: mysql://user:password@mysql:3306/db_name:这里定义了一个环境变量 DATABASE_URL,它包含了连接到数据库的完整 URL。这个 URL 包含了数据库类型(第一个“mysql”)、数据库服务器地址(第二个“mysql”,这里mysql 是 Docker 网络中的服务名或宿主机上的主机名,在4.3中定义)、端口(3306)、数据库名称(db_name)以及数据库用户名和密码(user:password)。这个环境变量将被 FastAPI 应用读取,用于配置数据库连接。

7.2 networks: default

  • external:
    • name: my_network:这行配置了服务使用的网络。default 是 Docker Compose 文件中定义的网络的名称,它被设置为使用一个已经存在的外部网络 my_network(在4.3中定义)。这意味着 my-fastapi 服务将连接到名为 my_network 的网络,这个网络需要在 Docker 中预先创建。

这个配置允许 my-fastapi 服务和 mysql 服务在同一个网络中通信,因为它们都在 my_network 网络中。这样,my-fastapi 服务可以通过网络别名 mysql 来访问 MySQL 服务,而不需要知道 MySQL 服务的实际 IP 地址。请注意,你需要确保 mysql 服务已经配置并启动,以便 my-fastapi 服务在启动时可以依赖它,例如使用如下命令:

docker-compose -f mysql-compose.yml up -d
docker-compose -f fastapi-compose.yml up -d

这些配置能够确保你在fastapi服务中使用环境变量“DATABASE_URL”连接数据库。


评论

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注