代码6:import asyncio
import logging
import aiomysql
from server.src.mvc.database import Database
from common.models import User
class ServerModel:
"""服务器模型"""
def __init__(self, controller):
self.controller = controller
self.db = Database()
async def init_database(self):
"""对数据库进行初始化"""
try:
await self.db.init_database()
except RuntimeError as e:
# 处理初始化失败场景
self.controller.update_status(e)
async def authenticate_user(self, username, password):
"""验证用户"""
try:
query = "SELECT user_id, username, role FROM users WHERE username = %s AND password = %s"
result = await self.db.execute_query(query, (username, password))
if not result:
return None
user_data = result[0]
return User(
user_id=user_data["user_id"],
username=user_data["username"],
role=user_data["role"]
)
except (RuntimeError, aiomysql.Error) as e:
logging.error(f"认证异常: {e}")
# 遵循返回None的设计约定
return None
代码7:import asyncio
import aiomysql
import logging
class Database:
"""异步数据库操作"""
def __init__(self, host="localhost", port=3306, user="root", password="123456", db="erp"):
"""异步配置数据库操作"""
# 地址
self.host = host
# 端口
self.port = port
# 登录账号
self.user = user
# 登录密码
self.password = password
# 数据库名称
self.db = db
self.pool = None
# 添加连接锁防止竞态条件
self.connection_lock = asyncio.Lock()
async def _ensure_connection(self):
"""连接数据库"""
async with self.connection_lock:
if self.pool is None:
try:
#先尝试连接到MySQL 服务器,不指定数据
temp_pool = await aiomysql.create_pool(
host=self.host,
port=self.port,
user=self.user,
password=self.password,
autocommit=True,
minsize=1,
maxsize=20
)
async with temp_pool.acquire() as conn:
async with conn.cursor() as cursor:
# 检查数据库是否存在
await cursor.execute(f"SHOW DATABASES LIKE '{self.db}'")
result = await cursor.fetchone()
if not result:
# 如果数据库不存在,则创建数据库
await cursor.execute(f"CREATE DATABASE {self.db}")
logging.info(f"数据库 {self.db} 创建成功")
# 关闭临时地址池
temp_pool.close()
await temp_pool.wait_closed()
# 创建执行数据库的连接池
self.pool = await aiomysql.create_pool(
host=self.host,
port=self.port,
user=self.user,
password=self.password,
db=self.db,
autocommit=True,
minsize=1,
maxsize=20, # 根据负载调整连接池大小
connect_timeout=10, # 连接超时时间(秒)
charset='utf8mb4', # 字符集设置
pool_recycle=3600 # 连接回收时间(秒)
)
logging.info("数据库连接池创建成功")
except (aiomysql.Error, OSError) as e:
logging.critical(f"数据库连接失败: {e}")
raise ConnectionError(f"Database connection failed: {e}")
async def disconnect(self):
"""关闭数据库连接"""
if self.pool:
# 关闭连接池
self.pool.close()
# 等待所有连接释放
await self.pool.wait_closed()
self.pool = None
logging.info("数据库连接已关闭")
async def init_database(self):
"""初始化数据库"""
try:
"""保证DDL操作"""
await self._ensure_connection()
async with self.pool.acquire() as conn:
async with conn.cursor() as cursor:
# 批量执行创建语句
ddl_commands = [
# 创建创建用户表,IF NOT EXISTS users可以使该表不存在时才会创建
"""CREATE TABLE IF NOT EXISTS users (
user_id INT AUTO_INCREMENT PRIMARY KEY,
username VARCHAR(50) UNIQUE NOT NULL,
password VARCHAR(255) NOT NULL,
role ENUM('admin', 'user') NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP)""",
# 创建产品表
"""CREATE TABLE IF NOT EXISTS products (
product_id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(100) NOT NULL,
price DECIMAL(10, 2) NOT NULL,
stock INT NOT NULL DEFAULT 0,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP)""",
# 创建订单表
"""CREATE TABLE IF NOT EXISTS orders (
order_id INT AUTO_INCREMENT PRIMARY KEY,
customer VARCHAR(100) NOT NULL,
product_id INT NOT NULL,
quantity INT NOT NULL,
status ENUM('pending', 'completed', 'cancelled') NOT NULL DEFAULT 'pending',
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (product_id) REFERENCES products(product_id))""",
# 创建角色表
"""CREATE TABLE IF NOT EXISTS roles (
role_id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(50) UNIQUE NOT NULL,
description VARCHAR(255),
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
)""",
# 创建权限表
"""CREATE TABLE IF NOT EXISTS permissions (
permission_id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(50) UNIQUE NOT NULL,
description VARCHAR(255),
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP)""",
# 创建角色-权限关联表
"""CREATE TABLE IF NOT EXISTS role_permissions (
role_id INT NOT NULL,
permission_id INT NOT NULL,
PRIMARY KEY (role_id, permission_id),
FOREIGN KEY (role_id) REFERENCES roles(role_id),
FOREIGN KEY (permission_id) REFERENCES permissions(permission_id)
)"""]
for cmd in ddl_commands:
await cursor.execute(cmd)
# 执行数据初始化
await conn.begin()
try:
# 初始化登录数据
await cursor.execute(
"""INSERT INTO users (username, password, role)
VALUES
('admin', 'admin123', 'admin'),
('user', 'user123', 'user')
ON DUPLICATE KEY UPDATE username=username""")
# 添加测试角色和权限
await cursor.execute(
"""INSERT INTO roles (name, description)
VALUES
('admin', '系统管理员'),
('user', '普通用户')
ON DUPLICATE KEY UPDATE name=name""")
# 创建许可表
await cursor.execute("""
INSERT INTO permissions (name, description)
VALUES
('view_products', '查看产品'),
('add_product', '添加产品'),
('edit_product', '编辑产品'),
('delete_product', '删除产品'),
('view_orders', '查看订单'),
('create_order', '创建订单'),
('edit_order', '编辑订单'),
('delete_order', '删除订单'),
('manage_users', '管理用户'),
('view_logs', '查看日志')
ON DUPLICATE KEY UPDATE name=name
""")
# 建立角色-权限关联
await cursor.execute("""
INSERT INTO role_permissions (role_id, permission_id)
VALUES
(1, 1), (1, 2), (1, 3), (1, 4),
(1, 5), (1, 6), (1, 7), (1, 8),
(1, 9), (1, 10), -- 管理员权限
(2, 1), (2, 5), (2, 6) -- 用户权限
ON DUPLICATE KEY UPDATE role_id=role_id
""")
await conn.commit()
logging.info("数据库初始化完成")
except Exception as e:
await conn.rollback()
logging.error(f"数据初始化失败: {e}")
raise
except Exception as e:
logging.exception("数据库初始化致命错误")
await self.disconnect()
raise RuntimeError(f"Init database failed: {e}") from e
async def execute_update(self, query, params=None):
"""执行更新"""
try:
await self._ensure_connection()
async with self.pool.acquire() as conn:
async with conn.cursor() as cursor:
await cursor.execute(query, params or ())
return cursor.rowcount
except (aiomysql.Error, RuntimeError) as e:
logging.error(f"执行更新失败: {e}\nQuery: {query}")
raise
async def execute_query(self, query, params=None):
"""执行查询"""
try:
await self._ensure_connection()
async with self.pool.acquire() as conn:
async with conn.cursor(aiomysql.DictCursor) as cursor:
await cursor.execute(query, params or ())
return await cursor.fetchall()
except (aiomysql.Error, RuntimeError) as e:
logging.error(f"执行查询失败: {e}\nQuery: {query}")
raise