关系型数据库-MYSQL
掌握 MySQL: 从 Docker 部署到 Python 高性能集成 (Ubuntu 24.04)
MySQL 是世界上最受欢迎的开源关系型数据库,是无数应用程序背后稳定可靠的数据基石。本指南将带您走过在现代 Linux 环境 (Ubuntu 24.04) 下,从部署到应用集成的完整流程。
使用 Docker 快速部署 MySQL
在 Ubuntu 24.04 上,使用 Docker 部署 MySQL 是最推荐的方式。它干净、隔离、可移植,并且不会污染您的主机环境。
部署 MySQL 容器
执行以下命令来启动一个 MySQL 的容器:
docker run -d \
--name mysql-server \
-p 3306:3306 \
-e MYSQL_ROOT_PASSWORD="Your_Super_Strong_Password" \
-v mysql-data:/var/lib/mysql \
mysql:latest
命令解析:
-d
: 后台分离模式 (Detached) 运行。--name mysql-server
: 为容器指定一个友好的名称。-p 3306:3306
: 将主机的 3306 端口映射到容器的 3306 端口。-e MYSQL_ROOT_PASSWORD="..."
: 关键! 设置 MySQLroot
用户的密码。请务必替换为您的强密码。-v mysql-data:/var/lib/mysql
: 关键! 创建一个 Docker 卷 (Volume)mysql-data
并挂载到容器内 MySQL 的数据目录。这确保了即使容器被删除,您的数据也能持久化保存。mysql:latest
: 指定使用的 MySQL 镜像及其版本。建议使用具体版本号而非latest
,以保证环境的一致性。
验证部署
# 查看正在运行的容器
docker ps
# 输出应包含名为 mysql-server 的容器,状态为 Up
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
... mysql:8.3 "docker-entrypoint.s…" 10 seconds ago Up 9 seconds 0.0.0.0:3306->3306/tcp, 33060/tcp mysql-server
终端连接与基础操作
现在,让我们进入容器内部,使用 MySQL 命令行客户端。
docker exec -it mysql-server mysql -u root -p
docker exec -it
: 以交互模式进入正在运行的mysql-server
容器。mysql -u root -p
: 在容器内执行mysql
命令,使用root
用户登录,-p
提示输入密码。
输入您之前设置的 MYSQL_ROOT_PASSWORD
后,您将看到 mysql>
提示符。
一些基础命令:
-- 显示所有数据库
SHOW DATABASES;
-- 创建一个新的数据库用于我们的应用
CREATE DATABASE my_app_db CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
-- 切换到新创建的数据库
USE my_app_db;
-- 查看当前数据库中的所有表 (现在应该是空的)
SHOW TABLES;
-- 退出客户端
EXIT;
安全第一:创建专用用户并限制 IP
永远不要在您的应用程序中使用 root
账户! 我们应该创建一个权限受限的专用用户。
再次进入 MySQL 客户端:
docker exec -it mysql-server mysql -u root -p
执行以下 SQL 命令:
-- 1. 创建一个新用户 'app_user'
-- '@' 后面是允许登录的主机。
-- '%' 表示任何主机,适合开发。
-- 在生产环境中,应限制为具体的应用服务器 IP,例如 '192.168.1.100'。
CREATE USER 'app_user'@'%' IDENTIFIED BY 'Another_Strong_Password';
-- 2. 授予该用户对 my_app_db 数据库的常用操作权限
GRANT SELECT, INSERT, UPDATE, DELETE ON my_app_db.* TO 'app_user'@'%';
-- 3. 刷新权限,使更改立即生效
FLUSH PRIVILEGES;
-- 4. 查看用户的权限
SHOW GRANTS FOR 'app_user'@'%';
-- 退出
EXIT;
现在,我们有了一个更安全的 app_user
,它只能操作 my_app_db
这个数据库。
Python 高性能集成
接下来,我们将使用 Python 连接并操作数据库。我们将分别为同步和异步场景提供带连接池的配置。
场景一:同步操作 (pymysql
+ DBUtils
连接池)
对于传统的同步应用(如 Flask, Django),每次请求都创建和销毁数据库连接开销巨大。使用连接池可以复用连接,显著提升性能。
安装依赖:
pip install pymysql DBUtils
配置与示例代码:
# db_config.py
import pymysql
from DBUtils.PooledDB import PooledDB
# 数据库连接参数
DB_CONFIG = {
'host': '127.0.0.1',
'port': 3306,
'user': 'app_user',
'password': 'Another_Strong_Password',
'database': 'my_app_db',
'charset': 'utf8mb4'
}
# 创建连接池
# creator: 指定创建连接的模块
# mincached: 初始化时,连接池中至少创建的空闲连接数
# maxcached: 连接池中最多闲置的连接数
# maxconnections: 连接池允许的最大连接数
# blocking: 连接池中无可用连接时,是否阻塞等待
pool = PooledDB(
creator=pymysql,
mincached=2,
maxcached=5,
maxconnections=10,
blocking=True,
**DB_CONFIG
)
def get_connection():
"""从连接池中获取一个连接"""
return pool.connection()
# main_sync.py
from db_config import get_connection
def setup_database():
"""初始化数据库表"""
conn = None
try:
conn = get_connection()
with conn.cursor() as cursor:
cursor.execute("""
CREATE TABLE IF NOT EXISTS users (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(50) NOT NULL,
email VARCHAR(100) UNIQUE
)
""")
conn.commit()
print("Table 'users' created successfully.")
finally:
if conn:
conn.close() # 关键:不是关闭连接,而是将其归还给连接池
def add_user(name, email):
"""添加一个新用户"""
conn = None
try:
conn = get_connection()
with conn.cursor() as cursor:
sql = "INSERT INTO `users` (`name`, `email`) VALUES (%s, %s)"
cursor.execute(sql, (name, email))
conn.commit()
print(f"User '{name}' added.")
except Exception as e:
print(f"Error adding user: {e}")
if conn:
conn.rollback()
finally:
if conn:
conn.close()
if __name__ == "__main__":
setup_database()
add_user("Alice", "alice@example.com")
add_user("Bob", "bob@example.com")
场景二:异步操作 (aiomysql
连接池)
对于现代异步框架(如 FastAPI, aiohttp),必须使用异步数据库驱动。aiomysql
是 pymysql
的异步版本。
安装依赖:
pip install aiomysql
配置与示例代码:
# db_config_async.py
import asyncio
import aiomysql
# 数据库连接参数 (与同步配置相同)
DB_CONFIG = {
'host': '127.0.0.1',
'port': 3306,
'user': 'app_user',
'password': 'Another_Strong_Password',
'db': 'my_app_db', # 注意:aiomysql 中参数名为 db
'charset': 'utf8mb4',
'autocommit': False # 建议在异步中手动控制事务
}
async def get_pool():
"""创建一个异步连接池"""
# minsize: 最小连接数
# maxsize: 最大连接数
return await aiomysql.create_pool(
minsize=2,
maxsize=10,
**DB_CONFIG
)
# main_async.py
import asyncio
from db_config_async import get_pool
async def setup_database(pool):
"""异步初始化数据库表"""
async with pool.acquire() as conn:
async with conn.cursor() as cursor:
await cursor.execute("""
CREATE TABLE IF NOT EXISTS products (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(100) NOT NULL,
price DECIMAL(10, 2)
)
""")
await conn.commit()
print("Table 'products' created successfully.")
async def add_product(pool, name, price):
"""异步添加一个新产品"""
async with pool.acquire() as conn: # 从池中获取连接
async with conn.cursor() as cursor: # 获取游标
try:
sql = "INSERT INTO `products` (`name`, `price`) VALUES (%s, %s)"
await cursor.execute(sql, (name, price))
await conn.commit()
print(f"Product '{name}' added.")
except Exception as e:
print(f"Error adding product: {e}")
await conn.rollback()
async def main():
pool = await get_pool()
await setup_database(pool)
# 并发执行添加操作
tasks = [
add_product(pool, "Laptop", 1299.99),
add_product(pool, "Mouse", 49.50)
]
await asyncio.gather(*tasks)
pool.close()
await pool.wait_closed()
if __name__ == "__main__":
asyncio.run(main())
连接池的核心价值
无论同步还是异步,连接池都通过复用已建立的 TCP 连接,避免了昂贵的连接握手和认证开销。在高并发场景下,这是保证数据库性能和稳定性的关键一环。
No comments to display
No comments to display