<think>我们参考了用户提供的引用,特别是引用[3]中展示了如何使用Python读取SQL文件并导入到MySQL数据库。用户的需求是使用Python将MySQL数据库文件(通常是.sql文件)导入到MySQL数据库中。
### 解决方案步骤
1. **连接数据库**:使用PyMySQL或mysql-connector-python等库建立与MySQL数据库的连接。
2. **读取SQL文件**:打开.sql文件,读取其中的SQL语句。
3. **分割SQL语句**:由于SQL文件通常包含多个语句,每个语句以分号(;)结尾,但可能包含函数、存储过程等复杂结构,因此需要谨慎分割。
4. **执行SQL语句**:逐条执行SQL语句,并提交事务。
### 完整代码示例
```python
import pymysql
import re
def import_sql_file(host, port, user, password, dbname, sql_file_path):
"""
将SQL文件导入到指定的MySQL数据库中
参数:
host: 数据库主机地址
port: 数据库端口
user: 数据库用户名
password: 数据库密码
dbname: 数据库名称
sql_file_path: SQL文件路径
"""
# 连接数据库
conn = pymysql.connect(
host=host,
port=port,
user=user,
password=password,
charset='utf8mb4',
database=dbname
)
cursor = conn.cursor()
try:
# 读取SQL文件
with open(sql_file_path, 'r', encoding='utf-8') as f:
sql_content = f.read()
# 预处理SQL内容:移除注释和可能干扰的字符
# 移除单行注释 (-- ...)
sql_content = re.sub(r'--.*', '', sql_content)
# 移除多行注释 (/* ... */)
sql_content = re.sub(r'/\*[\s\S]*?\*/', '', sql_content)
# 移除无用的空白字符(包括换行和多余空格)
sql_content = re.sub(r'\s+', ' ', sql_content).strip()
# 分割SQL语句(注意:分号可能出现在字符串中,这里简单分割,实际需要更复杂的处理)
# 但为了简单,我们假设每个语句以分号结束且分号不在字符串内
sql_commands = sql_content.split(';')
# 执行每条SQL语句
for command in sql_commands:
if command.strip(): # 跳过空语句
cursor.execute(command)
print(f"执行成功: {command[:50]}...") # 打印前50个字符
# 提交事务
conn.commit()
print("SQL文件导入成功!")
except Exception as e:
conn.rollback()
print(f"导入失败: {e}")
finally:
cursor.close()
conn.close()
# 使用示例
if __name__ == "__main__":
# 数据库配置
host = "localhost"
port = 3306
user = "root"
password = "your_password"
dbname = "your_database"
sql_file_path = "path/to/your/file.sql" # 替换为你的SQL文件路径
# 导入SQL文件
import_sql_file(host, port, user, password, dbname, sql_file_path)
```
### 关键点说明
1. **连接数据库**:使用`pymysql.connect`建立连接,并指定数据库名称(`dbname`)[^4]。
2. **读取SQL文件**:使用`open`函数以UTF-8编码读取文件内容。
3. **SQL内容预处理**:
- 移除单行注释(以`--`开头的行)[^3]。
- 移除多行注释(`/* ... */`)[^3]。
- 移除多余的空白字符(包括换行和连续空格),使SQL语句更紧凑。
4. **分割SQL语句**:使用分号(`;`)分割,但需要注意分号可能出现在字符串中。此示例简单处理,适用于大多数情况。对于复杂SQL(如包含存储过程、函数等),可能需要更高级的解析器。
5. **逐条执行SQL**:遍历分割后的SQL语句,跳过空语句,执行并打印执行状态。
6. **事务处理**:使用`commit`提交所有操作,如果出错则`rollback`回滚。
### 注意事项
- **字符编码**:确保SQL文件使用UTF-8编码,避免乱码问题。
- **大文件处理**:如果SQL文件非常大(几百MB以上),可能需要逐行读取并解析,避免内存不足。
- **特殊SQL语句**:如果SQL文件包含存储过程、函数或触发器,其中可能包含分号,上述简单分割方法可能出错。此时,可以使用更复杂的解析方法,例如使用正则表达式匹配`DELIMITER`命令(如果有)或者使用第三方库如`sqlparse`。
### 替代方案:使用命令行工具
如果环境允许,也可以直接使用MySQL命令行工具导入,效率更高:
```python
import subprocess
def import_sql_via_mysql_command(host, user, password, dbname, sql_file_path):
command = f"mysql -h {host} -u {user} -p{password} {dbname} < {sql_file_path}"
process = subprocess.Popen(command, shell=True)
process.wait()
if process.returncode == 0:
print("导入成功")
else:
print("导入失败")
# 注意:此方法需要系统中有mysql客户端,且密码中若有特殊字符需处理
```
### 进阶:使用sqlparse库处理复杂SQL
对于复杂的SQL文件,推荐使用`sqlparse`库进行分割:
```bash
pip install sqlparse
```
```python
import sqlparse
# 使用sqlparse分割
sql_commands = sqlparse.split(sql_content)
for command in sql_commands:
if command.strip():
cursor.execute(command)
```
`sqlparse`可以更智能地分割SQL语句,避免分号在字符串内或注释中的问题。
### 总结
本文提供了两种方法:
1. **使用Python逐条执行SQL语句**:适用于中小型SQL文件,需要处理注释和空白字符。
2. **调用系统命令**:使用`mysql`命令行工具,高效且简单,但需要系统支持。
根据实际需求选择合适的方法[^3][^5]。
§§相关问题§§
1. 如何将Excel数据导入MySQL数据库?
2. 如何使用Python导出MySQL数据库为SQL文件?
3. 如何处理大型SQL文件的导入?
4. 如何避免SQL文件导入中的编码问题?
5. 如何导入包含存储过程和函数的SQL文件?</think>### 使用Python将MySQL数据库文件(.sql)导入MySQL数据库
以下是完整的解决方案,支持大型SQL文件导入,包含注释处理、特殊字符转义和错误处理:
```python
import pymysql
import os
import re
import sys
from tqdm import tqdm # 进度条支持
def import_sql_file(host, port, user, password, dbname, sql_file_path):
"""
将SQL文件导入到MySQL数据库
参数:
host: 数据库主机地址
port: 数据库端口
user: 数据库用户名
password: 数据库密码
dbname: 数据库名称
sql_file_path: SQL文件路径
"""
try:
# 连接数据库
conn = pymysql.connect(
host=host,
port=port,
user=user,
password=password,
charset='utf8mb4',
autocommit=False # 手动提交事务
)
cur = conn.cursor()
# 创建数据库(如果不存在)
cur.execute(f"CREATE DATABASE IF NOT EXISTS `{dbname}` DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;")
conn.commit()
# 切换到目标数据库
cur.execute(f"USE `{dbname}`;")
# 读取SQL文件
print(f"正在读取SQL文件: {sql_file_path}")
with open(sql_file_path, 'r', encoding='utf-8') as f:
sql_content = f.read()
# 预处理SQL内容
# 1. 移除注释
sql_content = re.sub(r'-- .*\n', '', sql_content) # 移除单行注释
sql_content = re.sub(r'/\*[\s\S]*?\*/', '', sql_content) # 移除多行注释
# 2. 移除多余空行
sql_content = re.sub(r'\n\s*\n', '\n', sql_content)
# 3. 分割SQL语句
sql_commands = [cmd.strip() for cmd in sql_content.split(';\n') if cmd.strip()]
# 执行SQL语句
print(f"开始导入 {len(sql_commands)} 条SQL命令...")
success_count = 0
error_count = 0
# 使用进度条显示导入进度
for i, cmd in tqdm(enumerate(sql_commands), total=len(sql_commands)):
try:
# 处理特殊字符转义
if 'INSERT' in cmd.upper() or 'VALUES' in cmd.upper():
# 对INSERT语句中的特殊字符进行转义
cmd = re.sub(r"'(.*?)'",
lambda m: f"'{pymysql.converters.escape_string(m.group(1))}'",
cmd)
cur.execute(cmd)
success_count += 1
except Exception as e:
error_count += 1
print(f"\n错误在执行命令 #{i+1}: {e}")
print(f"问题命令: {cmd[:100]}...")
# 提交事务
conn.commit()
print(f"\n导入完成! 成功: {success_count}, 失败: {error_count}")
return True
except Exception as e:
print(f"导入失败: {e}")
return False
finally:
if 'cur' in locals():
cur.close()
if 'conn' in locals():
conn.close()
# 使用示例
if __name__ == "__main__":
# 数据库配置
DB_HOST = "localhost"
DB_PORT = 3306
DB_USER = "root"
DB_PASSWORD = "your_password"
DB_NAME = "mydatabase"
# SQL文件路径
SQL_FILE = "path/to/your/database.sql" # 替换为你的SQL文件路径
# 执行导入
result = import_sql_file(
host=DB_HOST,
port=DB_PORT,
user=DB_USER,
password=DB_PASSWORD,
dbname=DB_NAME,
sql_file_path=SQL_FILE
)
if result:
print("✅ 数据库导入成功!")
else:
print("❌ 数据库导入失败")
```
### 使用前准备
1. **安装依赖库**:
```bash
pip install pymysql tqdm
```
2. **配置参数**:
```python
# 数据库配置
DB_HOST = "localhost" # MySQL主机地址
DB_PORT = 3306 # MySQL端口
DB_USER = "root" # MySQL用户名
DB_PASSWORD = "your_password" # MySQL密码
DB_NAME = "mydatabase" # 目标数据库名
# SQL文件路径
SQL_FILE = "path/to/your/database.sql" # 替换为实际SQL文件路径
```
### 功能说明
1. **智能预处理**:
- 自动移除SQL注释(单行和多行注释)[^3]
- 处理多余空行和空白字符
- 分割SQL文件为独立命令
2. **特殊字符处理**:
- 自动转义INSERT语句中的特殊字符
- 支持UTF-8编码,避免中文乱码
3. **事务管理**:
- 使用手动提交事务(autocommit=False)
- 确保数据一致性
4. **进度反馈**:
- 使用tqdm显示导入进度条
- 详细统计成功/失败命令数量
5. **错误处理**:
- 捕获并显示错误命令片段
- 数据库连接自动关闭
### 大型文件处理技巧
对于超过100MB的大型SQL文件:
```python
# 替代直接读取整个文件的方法
def process_large_sql_file(conn, cur, file_path):
"""处理大型SQL文件的替代方法"""
buffer = ""
with open(file_path, 'r', encoding='utf-8') as f:
for line in f:
# 跳过注释行
if line.startswith('--') or line.startswith('/*'):
continue
buffer += line
# 遇到分号时执行
if ';' in line:
try:
cur.execute(buffer)
buffer = ""
except Exception as e:
print(f"执行错误: {e}")
buffer = ""
# 提交剩余命令
if buffer.strip():
cur.execute(buffer)
conn.commit()
```
### 常见问题解决
1. **编码问题**:
```python
# 在连接字符串中添加编码设置
conn = pymysql.connect(
charset='utf8mb4',
init_command='SET NAMES UTF8MB4'
)
```
2. **超时问题**:
```python
# 增加超时设置
conn = pymysql.connect(
connect_timeout=30,
read_timeout=300
)
```
3. **内存不足**:
- 使用分块读取方法(如上所示)
- 禁用进度条(删除tqdm)
4. **特殊语法错误**:
```python
# 在导入前添加SQL模式设置
cur.execute("SET sql_mode = 'NO_ENGINE_SUBSTITUTION';")
```
### 替代方案:使用命令行工具
对于超大SQL文件(>1GB),建议直接使用MySQL命令行工具:
```python
import subprocess
def import_via_commandline(host, user, password, dbname, sql_file):
"""使用mysql命令行工具导入"""
cmd = [
'mysql',
f'-h{host}',
f'-u{user}',
f'-p{password}',
dbname,
f'-e "source {sql_file}"'
]
result = subprocess.run(cmd, capture_output=True, text=True)
if result.returncode == 0:
print("导入成功")
else:
print(f"导入失败: {result.stderr}")
```
此方法效率更高但需要系统安装MySQL客户端[^5]。