数据分析agent二:Mysql镜像 docker拉取 测试
·
## docker run --name my-mysql -e MYSQL_ROOT_PASSWORD=happy23 -d -p 3307:3306 mysql:8.0.41
docker run --name my-mysql -e MYSQL_ROOT_PASSWORD=happy23 -d -p 3307:3306 mysql:latest
# 四,拉取mysql 镜像地址
bash
docker pull mysql:latest
或直接运行:
bash
docker run --name my-mysql -e MYSQL_ROOT_PASSWORD=happy23 -d -p 3307:3306 mysql:latest
### 下载完成后,检查容器状态
bash
### 查看容器是否在运行
docker ps
### 应该能看到名为 my-mysql 的容器,状态为 Up
连接测试
容器运行后,用以下方式测试连接:
### 方式一:通过命令行连接
bash
docker exec -it my-mysql mysql -uroot -phappy23
### 方式二:通过 Windows 客户端连接
地址:localhost 或 127.0.0.1
端口:3307
用户名:root
密码:happy23
# =================================================
### 在 MySQL 里,root 是一个特殊的超级管理员账号,官方不推荐也不支持直接将其“重命名”。不过,我们可以通过另一种方式实现同样的目的:创建一个拥有全部权限、可以替代 root 的新用户,然后停用 root 用户。
### 下面是在你的 Docker MySQL 容器中实现这个目标的具体步骤。
# 操作流程
#### 进入容器:在终端执行以下命令,进入 MySQL 容器的命令行界面,my-mysql 替换成你的容器名:
bash
docker exec -it my-mysql mysql -u root -p
然后输入你之前设置的 happy23 密码。
#### 创建新管理用户:在 MySQL 命令行中执行以下命令,创建一个名为 newadmin,密码为 your_strong_password 的新用户,并赋予它与 root 相同的所有权限:
```sql
-- 创建一个可以从任何主机连接的新用户
CREATE USER 'newadmin'@'%' IDENTIFIED BY 'your_strong_password';
-- 授予该用户所有数据库的所有权限
GRANT ALL PRIVILEGES ON *.* TO 'newadmin'@'%' WITH GRANT OPTION;
-- 刷新权限,使设置立即生效
FLUSH PRIVILEGES;
这里将 'newadmin'@'%' 中的 % 替换为 'localhost',可以限制该用户仅能从容器内部或本地主机登录。
验证并切换用户:输入 exit; 退出 MySQL 命令行,然后用新用户尝试登录,验证其功能:
```
#### docker exec -it my-mysql mysql -u newadmin -p
(可选)禁用 root 用户:确认新用户可用后,回到 MySQL 命令行,执行以下命令删除 root 用户:
⚠️ 警告:执行此操作前,请务必确认你的新管理员账户一切正常,否则可能导致数据库无法管理。
#### sql
-- 删除 root 用户(注意 host 可能有多个,如 'localhost', '%')
DROP USER 'root'@'localhost';
DROP USER 'root'@'%';
-- 刷新权限
FLUSH PRIVILEGES;
## 💡 一些说明
为什么不直接用 RENAME USER? MySQL 的 RENAME USER 语句确实存在,但它通常不推荐用于 root 用户,因为这可能影响一些内部对象(如存储过程、视图)的定义者(DEFINER)属性,导致它们失效或产生安全问题。创建新用户是更安全和标准的做法。
关于连接:创建新用户后,从 Windows 宿主机或其他客户端连接 MySQL 时,只需要将用户名从 root 换成你新创建的用户名(如 newadmin),连接地址 localhost、端口 3307 和密码保持不变。
## 📝 总结
简单来说,完成后的结果如下:
## 项目 说明
原 root 用户 密码 happy23,默认情况下会被保留或安全移除
新管理员用户 用户名 newadmin,密码 your_strong_password,拥有全部权限
连接方式 将客户端或应用中的用户名从 root 替换为 newadmin 即可

import pymysql
from pymysql.cursors import DictCursor
from contextlib import contextmanager
from typing import List, Dict, Any, Optional, Union
import logging
# 配置日志
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
logger = logging.getLogger(__name__)
class MySQLClientManager:
"""
MySQL 数据库客户端管理类
支持连接管理、CRUD 操作、事务处理等
"""
def __init__(
self,
host: str = 'localhost',
port: int = 3306,
user: str = 'root',
password: str = '',
database: str = '',
charset: str = 'utf8mb4',
autocommit: bool = False,
pool_size: int = 5,
auto_create_db: bool = False,
**kwargs
):
"""
初始化 MySQL 连接配置
Args:
host: 数据库主机地址
port: 端口号
user: 用户名
password: 密码
database: 数据库名称
charset: 字符集
autocommit: 是否自动提交
pool_size: 连接池大小(目前仅配置,后续可扩展)
auto_create_db: 是否自动创建数据库(如果不存在)
**kwargs: 其他 pymysql 参数
"""
self.config = {
'host': host,
'port': port,
'user': user,
'password': password,
'database': database,
'charset': charset,
'autocommit': autocommit,
'cursorclass': DictCursor,
**kwargs
}
self._connection = None
self.pool_size = pool_size
# 如果需要自动创建数据库
if auto_create_db and database:
self._ensure_database_exists()
logger.info(f"MySQLClientManager 初始化完成: {host}:{port}/{database}")
def _ensure_database_exists(self):
"""确保数据库存在,如果不存在则创建"""
database_name = self.config['database']
try:
# 先不指定数据库连接
temp_config = self.config.copy()
temp_config.pop('database')
temp_conn = pymysql.connect(**temp_config)
with temp_conn.cursor() as cursor:
cursor.execute(f"CREATE DATABASE IF NOT EXISTS {database_name}")
temp_conn.close()
logger.info(f"数据库 {database_name} 已创建或已存在")
except Exception as e:
logger.error(f"创建数据库失败: {e}")
raise
def _get_connection(self):
"""获取数据库连接(单例模式)"""
if self._connection is None:
try:
self._connection = pymysql.connect(**self.config)
logger.debug("数据库连接已建立")
except pymysql.Error as e:
logger.error(f"数据库连接失败: {e}")
raise
else:
# 检查连接是否存活
try:
self._connection.ping(reconnect=True)
except pymysql.Error:
logger.warning("连接已断开,重新建立连接")
self._connection = pymysql.connect(**self.config)
return self._connection
def close(self):
"""关闭数据库连接"""
if self._connection:
self._connection.close()
self._connection = None
logger.debug("数据库连接已关闭")
@contextmanager
def get_cursor(self):
"""
获取游标的上下文管理器
自动处理事务提交/回滚
"""
conn = self._get_connection()
cursor = conn.cursor()
try:
yield cursor
if not self.config.get('autocommit', False):
conn.commit()
except Exception as e:
if not self.config.get('autocommit', False):
conn.rollback()
logger.error(f"数据库操作失败: {e}")
raise
finally:
cursor.close()
# ==================== 查询操作 ====================
def execute_query(self, sql: str, params: Optional[Union[tuple, dict]] = None) -> List[Dict[str, Any]]:
"""
执行查询语句,返回所有结果
Args:
sql: SQL 语句
params: 参数(tuple 或 dict)
Returns:
查询结果列表,每行是一个字典
"""
with self.get_cursor() as cursor:
cursor.execute(sql, params or ())
result = cursor.fetchall()
logger.debug(f"查询成功,返回 {len(result)} 行")
return result
def execute_query_one(self, sql: str, params: Optional[Union[tuple, dict]] = None) -> Optional[Dict[str, Any]]:
"""
执行查询语句,返回单条结果
Args:
sql: SQL 语句
params: 参数
Returns:
单条结果字典,如果没有结果则返回 None
"""
with self.get_cursor() as cursor:
cursor.execute(sql, params or ())
result = cursor.fetchone()
logger.debug(f"查询成功,返回 {'1 行' if result else '0 行'}")
return result
def execute_insert(self, table: str, data: Dict[str, Any]) -> int:
"""
插入单条数据
Args:
table: 表名
data: 要插入的数据字典 {列名: 值}
Returns:
插入的行 ID
"""
columns = ', '.join(data.keys())
placeholders = ', '.join(['%s'] * len(data))
sql = f"INSERT INTO {table} ({columns}) VALUES ({placeholders})"
with self.get_cursor() as cursor:
cursor.execute(sql, tuple(data.values()))
last_id = cursor.lastrowid
logger.info(f"插入成功: {table}, ID={last_id}")
return last_id
def execute_insert_batch(self, table: str, data_list: List[Dict[str, Any]]) -> int:
"""
批量插入数据
Args:
table: 表名
data_list: 要插入的数据字典列表
Returns:
插入的行数
"""
if not data_list:
return 0
columns = ', '.join(data_list[0].keys())
placeholders = ', '.join(['%s'] * len(data_list[0]))
sql = f"INSERT INTO {table} ({columns}) VALUES ({placeholders})"
# 构建参数列表
params_list = [tuple(d.values()) for d in data_list]
with self.get_cursor() as cursor:
affected = cursor.executemany(sql, params_list)
logger.info(f"批量插入成功: {table}, 共 {affected} 行")
return affected
def execute_update(self, table: str, data: Dict[str, Any], where: str, where_params: Optional[tuple] = None) -> int:
"""
更新数据
Args:
table: 表名
data: 要更新的数据字典 {列名: 值}
where: WHERE 条件(如 "id = %s")
where_params: WHERE 条件的参数
Returns:
受影响的行数
"""
set_clause = ', '.join([f"{k} = %s" for k in data.keys()])
sql = f"UPDATE {table} SET {set_clause} WHERE {where}"
params = tuple(data.values()) + (where_params or ())
with self.get_cursor() as cursor:
affected = cursor.execute(sql, params)
logger.info(f"更新成功: {table}, 影响 {affected} 行")
return affected
def execute_delete(self, table: str, where: str, where_params: Optional[tuple] = None) -> int:
"""
删除数据
Args:
table: 表名
where: WHERE 条件(如 "id = %s")
where_params: WHERE 条件的参数
Returns:
受影响的行数
"""
sql = f"DELETE FROM {table} WHERE {where}"
with self.get_cursor() as cursor:
affected = cursor.execute(sql, where_params or ())
logger.info(f"删除成功: {table}, 影响 {affected} 行")
return affected
def execute_sql(self, sql: str, params: Optional[Union[tuple, dict]] = None) -> int:
"""
执行任意 SQL 语句(DDL/DML)
Args:
sql: SQL 语句
params: 参数
Returns:
受影响的行数
"""
with self.get_cursor() as cursor:
affected = cursor.execute(sql, params or ())
logger.debug(f"SQL 执行成功,影响 {affected} 行")
return affected
# ==================== 事务操作 ====================
def begin_transaction(self):
"""开始事务(需要 autocommit=False)"""
conn = self._get_connection()
conn.begin()
logger.debug("事务已开始")
def commit_transaction(self):
"""提交事务"""
conn = self._get_connection()
conn.commit()
logger.debug("事务已提交")
def rollback_transaction(self):
"""回滚事务"""
conn = self._get_connection()
conn.rollback()
logger.debug("事务已回滚")
# ==================== 辅助方法 ====================
def table_exists(self, table_name: str) -> bool:
"""检查表是否存在"""
sql = """
SELECT COUNT(*) as count
FROM information_schema.tables
WHERE table_schema = %s AND table_name = %s
"""
result = self.execute_query_one(sql, (self.config['database'], table_name))
return result and result['count'] > 0
def get_table_info(self, table_name: str) -> List[Dict[str, Any]]:
"""获取表结构信息"""
sql = f"DESCRIBE {table_name}"
return self.execute_query(sql)
def count(self, table: str, where: Optional[str] = None, where_params: Optional[tuple] = None) -> int:
"""统计表行数"""
sql = f"SELECT COUNT(*) as total FROM {table}"
if where:
sql += f" WHERE {where}"
result = self.execute_query_one(sql, where_params or ())
return result['total'] if result else 0
# ==================== 使用示例 ====================
if __name__ == "__main__":
# 创建客户端实例(自动创建数据库)
client = MySQLClientManager(
host='127.0.0.1',
port=3307,
user='root',
password='happy23',
database='test_db',
autocommit=False,
auto_create_db=True # 自动创建数据库
)
try:
# 创建测试表
create_table_sql = """
CREATE TABLE IF NOT EXISTS users (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(50) NOT NULL,
age INT,
email VARCHAR(100),
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
)
"""
client.execute_sql(create_table_sql)
print("✅ 表创建成功")
# 插入单条数据
user_data = {'name': '张三', 'age': 25, 'email': 'zhangsan@example.com'}
user_id = client.execute_insert('users', user_data)
print(f"✅ 插入用户 ID: {user_id}")
# 批量插入数据
users = [
{'name': '李四', 'age': 30, 'email': 'lisi@example.com'},
{'name': '王五', 'age': 28, 'email': 'wangwu@example.com'},
{'name': '赵六', 'age': 35, 'email': 'zhaoliu@example.com'},
]
affected = client.execute_insert_batch('users', users)
print(f"✅ 批量插入 {affected} 条记录")
# 查询数据(年龄大于25的)
result = client.execute_query("SELECT * FROM users WHERE age > %s", (25,))
print(f"\n📋 年龄大于25的用户:")
for row in result:
print(f" - ID: {row['id']}, 姓名: {row['name']}, 年龄: {row['age']}, 邮箱: {row['email']}")
# 查询单条数据
user = client.execute_query_one("SELECT * FROM users WHERE id = %s", (user_id,))
if user:
print(f"\n📋 ID={user_id} 的用户: {user['name']}, 年龄: {user['age']}")
# 更新数据
affected = client.execute_update('users', {'age': 26}, 'id = %s', (user_id,))
print(f"✅ 更新了 {affected} 条记录")
# 再次查询验证更新
user = client.execute_query_one("SELECT * FROM users WHERE id = %s", (user_id,))
if user:
print(f"📋 更新后用户 {user['name']} 的年龄: {user['age']}")
# 统计总记录数
total = client.count('users')
print(f"\n📊 用户总数: {total}")
# 统计年龄大于30的记录数
count_gt_30 = client.count('users', 'age > %s', (30,))
print(f"📊 年龄大于30的用户数: {count_gt_30}")
# 检查表是否存在
exists = client.table_exists('users')
print(f"\n📋 表 users 是否存在: {exists}")
# 获取表结构
table_info = client.get_table_info('users')
print(f"\n📋 表结构:")
for field in table_info:
print(f" - {field['Field']}: {field['Type']}")
# 删除数据(注释掉以避免误删)
# affected = client.execute_delete('users', 'id = %s', (user_id,))
# print(f"✅ 删除了 {affected} 条记录")
except Exception as e:
print(f"❌ 操作失败: {e}")
import traceback
traceback.print_exc()
finally:
# 关闭连接
client.close()
print("\n✅ 数据库连接已关闭")

更多推荐


所有评论(0)