一、概述

MySQL 类是一个用于封装与 MySQL 数据库交互操作的工具类,支持链式调用风格来实现增删改查等常见数据库操作。它提供了一系列方便的方法,允许用户轻松地进行数据库连接、数据查询、插入、更新和删除等操作,同时还支持事务处理和批量插入功能。

二、类的主要属性和方法

2.1 属性

  • server:数据库服务器地址。
  • port:数据库服务器端口号。
  • database:要连接的数据库名称。
  • username:登录数据库的用户名。
  • password:登录数据库的密码。
  • tableName:当前操作的表名。
  • columns:用于存储查询时指定的列名列表。
  • whereClause:存储查询的 WHERE 条件语句。
  • orderByColumn:用于指定排序的列名。
  • orderByDescending:表示排序是否为降序,默认是升序(false)。
  • limit:用于指定查询结果的限制数量。
  • connection:数据库连接对象。

2.2 方法

2.2.1 构造函数

public MySQL(string server, int port)
  • 功能:接收数据库服务器地址和端口号,初始化相关属性并尝试建立数据库连接。
  • 参数
    • server:数据库服务器地址。
    • port:数据库服务器端口号。

2.2.2 链式方法

2.2.2.1 数据库连接信息设置
  • Database(string database):设置要连接的数据库名称。返回当前 MySQL 类实例,方便继续链式调用。
  • User(string username):设置登录用户名。返回当前 MySQL 类实例,方便继续链式调用。
  • Password(string password):设置登录密码。返回当前 MySQL 类实例,方便继续链式调用。
2.2.2.2 操作表设置
  • Table(string tableName):设置当前操作表名。返回当前 MySQL 类实例,方便继续链式调用。
2.2.2.3 列选择设置
  • Col(string column):添加单个列名到列名列表,用于指定查询时选择的列。返回当前 MySQL 类实例,方便继续链式调用。
  • Col(List<string> columns):添加多个列名到列名列表,用于指定查询时选择的列。返回当前 MySQL 类实例,方便继续链式调用。
  • 示例
    MySQL mysql = new MySQL("localhost", 3306)
    .Database("testdb")
    .User("root")
    .Password("password")
    .Table("users")
    .Col("Name")
    .Col("Age");
    DataTable result = mysql.All();

    上述代码中,通过 Col 方法指定了查询 users 表时只选择 NameAge 两列。

2.2.2.4 查询条件设置
  • Where(string whereClause):设置查询的 WHERE 条件语句。返回当前 MySQL 类实例,方便继续链式调用。
  • ID(int id):设置 WHERE 条件为根据 ID 字段来筛选某一条特定记录,相当于 Where("ID = " + id)。返回当前 MySQL 类实例,方便继续链式调用。
  • 示例
    MySQL mysql = new MySQL("localhost", 3306)
    .Database("testdb")
    .User("root")
    .Password("password")
    .Table("users")
    .Where("Age > 20");
    DataTable result = mysql.All();

    上述代码中,通过 Where 方法设置查询条件,只查询 users 表中 Age 大于 20 的记录。

MySQL mysql = new MySQL("localhost", 3306)
    .Database("testdb")
    .User("root")
    .Password("password")
    .Table("users")
    .ID(1);
DataRow user = mysql.One();

上述代码中,通过 ID 方法设置查询条件,只查询 users 表中 ID 为 1 的记录。

2.2.2.5 排序设置
  • By(string orderByColumn, bool descending = false):设置排序字段以及是否降序排序(默认为升序)。返回当前 MySQL 类实例,方便继续链式调用。
  • 示例
    MySQL mysql = new MySQL("localhost", 3306)
    .Database("testdb")
    .User("root")
    .Password("password")
    .Table("users")
    .By("Age", true);
    DataTable result = mysql.All();

    上述代码中,通过 By 方法设置按照 Age 字段降序排序查询 users 表的记录。

2.2.2.6 分页设置
  • Lim(int limit):设置查询结果限制数量,可用于实现分页功能。返回当前 MySQL 类实例,方便继续链式调用。
  • 示例
    // 假设每页显示 10 条记录,查询第 2 页的数据
    int pageSize = 10;
    int pageNumber = 2;
    int offset = (pageNumber - 1) * pageSize;
    MySQL mysql = new MySQL("localhost", 3306)
    .Database("testdb")
    .User("root")
    .Password("password")
    .Table("users")
    .Where("Age > 20")
    .Lim(pageSize);
    // 在实际应用中,可能需要在 SQL 生成部分添加 OFFSET 支持,当前代码可扩展修改实现
    // 这里仅展示 Lim 方法用于限制每页数量
    DataTable result = mysql.All();

    上述代码中,通过 Lim 方法设置每页显示 10 条记录,结合页码计算偏移量,可实现分页查询。

2.2.3 查询方法

  • All():执行查询并返回包含所有符合条件的数据的 DataTable 对象,用于获取多条查询结果。
  • AllAsync(CancellationToken cancellationToken = default):异步版本的 All() 方法。
  • One():执行查询并返回符合条件的第一条数据(如果有),以 DataRow 对象形式返回,用于获取单条查询结果。

2.2.4 数据操作方法

  • Insert(Dictionary<string, object> values):插入数据,接收一个字典,键为要插入的列名,值为对应列要插入的值,执行插入操作后返回受影响的行数。
  • Update(Dictionary<string, object> values):更新数据,接收一个字典,键为要更新的列名,值为对应列要更新的值,执行更新操作后返回受影响的行数。
  • Delete():删除数据,根据之前设置的 WHERE 条件(如果有)构建 DELETE 语句,执行删除操作后返回受影响的行数。

2.2.5 其他方法

  • Close():关闭数据库连接。判断连接对象是否存在且处于打开状态,如果是则关闭连接,释放数据库连接资源。
  • Query(string sql):执行自定义数据库指令,接收一个自定义的 SQL 语句字符串作为参数,打开数据库连接后执行该语句,返回受影响的行数。使用时要注意防止 SQL 注入,可使用参数化查询。
  • ExecuteTransaction(Action<MySqlTransaction> action):事务处理方法,接收一个包含事务操作的委托。在事务中执行一系列数据库操作,如果其中一个操作失败,整个事务将回滚。
  • BulkInsert(List<Dictionary<string, object>> dataList):批量插入方法,接收一个包含多个字典的列表,每个字典表示一条要插入的数据,返回受影响的行数。

三、使用示例

3.1 初始化数据库连接

using XL.Database;

// 创建 MySQL 实例
MySQL mysql = new MySQL("localhost", 3306)
    .Database("testdb")
    .User("root")
    .Password("password");

3.2 查询数据

3.2.1 查询所有数据

// 设置要操作的表
mysql.Table("users");

// 查询所有用户数据
DataTable allUsers = mysql.All();
foreach (DataRow row in allUsers.Rows)
{
    Console.WriteLine($"ID: {row["ID"]}, Name: {row["Name"]}");
}

3.2.2 异步查询所有数据

// 异步查询所有用户数据
var task = mysql.AllAsync();
task.Wait();
DataTable allUsersAsync = task.Result;
foreach (DataRow row in allUsersAsync.Rows)
{
    Console.WriteLine($"ID: {row["ID"]}, Name: {row["Name"]}");
}

3.2.3 查询单条数据

// 根据 ID 查询单条用户数据
DataRow user = mysql.ID(1).One();
if (user != null)
{
    Console.WriteLine($"ID: {user["ID"]}, Name: {user["Name"]}");
}

3.3 插入数据

// 插入一条新用户数据
Dictionary<string, object> newUser = new Dictionary<string, object>
{
    { "Name", "John Doe" },
    { "Age", 30 }
};
int rowsAffected = mysql.Insert(newUser);
Console.WriteLine($"插入 {rowsAffected} 条记录");

3.4 更新数据

// 更新用户数据
Dictionary<string, object> updatedUser = new Dictionary<string, object>
{
    { "Age", 31 }
};
int updatedRows = mysql.ID(1).Update(updatedUser);
Console.WriteLine($"更新 {updatedRows} 条记录");

3.5 删除数据

// 删除用户数据
int deletedRows = mysql.ID(1).Delete();
Console.WriteLine($"删除 {deletedRows} 条记录");

3.6 执行自定义 SQL 语句

// 执行自定义 SQL 语句
string sql = "CREATE TABLE IF NOT EXISTS new_table (ID INT PRIMARY KEY AUTO_INCREMENT, Name VARCHAR(50))";
int result = mysql.Query(sql);
Console.WriteLine($"执行自定义 SQL 语句,受影响的行数: {result}");

3.7 事务处理

// 事务处理示例
mysql.ExecuteTransaction(transaction =>
{
    try
    {
        // 插入一条数据
        Dictionary<string, object> data1 = new Dictionary<string, object>
        {
            { "Name", "Transaction User 1" },
            { "Age", 25 }
        };
        using (MySqlCommand command1 = new MySqlCommand($"INSERT INTO users (Name, Age) VALUES (@Name, @Age)", mysql.GetConnection(), transaction))
        {
            command1.Parameters.AddWithValue("@Name", data1["Name"]);
            command1.Parameters.AddWithValue("@Age", data1["Age"]);
            command1.ExecuteNonQuery();
        }
        // 更新一条数据
        Dictionary<string, object> data2 = new Dictionary<string, object>
        {
            { "Age", 26 }
        };
        using (MySqlCommand command2 = new MySqlCommand($"UPDATE users SET Age = @Age WHERE Name = 'Transaction User 1'", mysql.GetConnection(), transaction))
        {
            command2.Parameters.AddWithValue("@Age", data2["Age"]);
            command2.ExecuteNonQuery();
        }
    }
    catch (Exception ex)
    {
        throw new Exception("事务执行出错", ex);
    }
});

3.8 批量插入

// 批量插入数据
List<Dictionary<string, object>> dataList = new List<Dictionary<string, object>>
{
    new Dictionary<string, object>
    {
        { "Name", "Bulk User 1" },
        { "Age", 20 }
    },
    new Dictionary<string, object>
    {
        { "Name", "Bulk User 2" },
        { "Age", 21 }
    }
};
int bulkInsertRows = mysql.BulkInsert(dataList);
Console.WriteLine($"批量插入 {bulkInsertRows} 条记录");

3.9 关闭数据库连接

// 关闭数据库连接
mysql.Close();

四、注意事项

  • 在使用链式调用时,要确保正确设置数据库连接信息(如数据库名、用户名、密码)和操作表名。
  • 在执行 SQL 语句时,要注意防止 SQL 注入,可使用参数化查询。
  • 在使用事务处理时,要确保事务内的操作正确,避免因异常导致事务回滚。
  • 在使用批量插入时,要确保传入的数据列表不为空。

五、代码

using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using MySql.Data.MySqlClient;
namespace XL.Database
{
    // MySQL类用于封装与MySQL数据库的交互操作,支持链式调用风格来实现增删改查等常见数据库操作
    public class MySQL
    {
        // 数据库服务器地址
        private string server;
        // 数据库服务器端口号
        private int port;
        // 要连接的数据库名称
        private string database;
        // 登录数据库的用户名
        private string username;
        // 登录数据库的密码
        private string password;
        // 当前操作的表名
        private string tableName;
        // 用于存储查询时指定的列名列表,初始为空,后续通过Col方法添加列名
        private List<string> columns = [];
        // 存储查询的WHERE条件语句,初始为空,通过Where方法设置
        private string whereClause;
        // 用于指定排序的列名,初始为空,通过By方法设置
        private string orderByColumn;
        // 表示排序是否为降序,默认是升序(false),通过By方法设置
        private bool orderByDescending;
        // 用于指定查询结果的限制数量,初始为0,通过Lim方法设置
        private int limit;
        // 用于保存数据库连接对象,初始为null,在实例化时尝试创建长连接
        private MySqlConnection connection;
        // 连接池管理
        private static readonly ConcurrentDictionary<string, string> connectionStrings = new();
        // 构造函数,接收数据库服务器地址和端口号,初始化相关属性并尝试建立数据库连接
        public MySQL(string server, int port)
        {
            this.server = server;
            this.port = port;
            this.database = "";
            this.username = "";
            this.password = "";
            this.connection = null;
            // 生成连接池key
            string poolKey = $"{server}:{port}";
            // 存储连接字符串
            string connectionString = $"server={server};port={port};database={database};user={username};password={password};Connection Timeout=15;pooling=true;min pool size=1;max pool size=100;";
            connectionStrings[poolKey] = connectionString;
            try
            {
                // 创建新连接
                connection = new MySqlConnection(connectionString);
                connection.Open();
            }
            catch (MySqlException ex)
            {
                // 记录日志
                LogError($"数据库连接创建失败: {ex.Message}");
                throw new DatabaseConnectionException("数据库连接失败", ex);
            }
        }
        // 自定义数据库连接异常
        public class DatabaseConnectionException : Exception
        {
            public DatabaseConnectionException(string message, Exception innerException) 
                : base(message, innerException) { }
        }
        // 自定义数据库操作异常
        public class DatabaseOperationException : Exception
        {
            public DatabaseOperationException(string message, Exception innerException)
                : base(message, innerException) { }
        }
        // 设置要连接的数据库名称的链式方法,返回当前MySQL类实例,方便继续链式调用
        public MySQL Database(string database)
        {
            this.database = database;
            return this;
        }
        // 设置登录用户名的链式方法,返回当前MySQL类实例,方便继续链式调用
        public MySQL User(string username)
        {
            this.username = username;
            return this;
        }
        // 设置登录密码的链式方法,返回当前MySQL类实例,方便继续链式调用
        public MySQL Password(string password)
        {
            this.password = password;
            return this;
        }
        // 设置当前操作表名的链式方法,返回当前MySQL类实例,方便继续链式调用
        public MySQL Table(string tableName)
        {
            this.tableName = tableName;
            return this;
        }
        // 添加单个列名到列名列表的链式方法,用于指定查询时选择的列,返回当前MySQL类实例,方便继续链式调用
        public MySQL Col(string column)
        {
            columns.Add(column);
            return this;
        }
        // 添加多个列名到列名列表的链式方法,用于指定查询时选择的列,返回当前MySQL类实例,方便继续链式调用
        public MySQL Col(List<string> columns)
        {
            this.columns.AddRange(columns);
            return this;
        }
        // 设置查询的WHERE条件语句的链式方法,返回当前MySQL类实例,方便继续链式调用
        public MySQL Where(string whereClause)
        {
            this.whereClause = whereClause;
            return this;
        }
        // 设置排序字段以及是否降序排序(默认为升序)的链式方法,返回当前MySQL类实例,方便继续链式调用
        public MySQL By(string orderByColumn, bool descending = false)
        {
            this.orderByColumn = orderByColumn;
            this.orderByDescending = descending;
            return this;
        }
        // 设置查询结果限制数量的链式方法,返回当前MySQL类实例,方便继续链式调用
        public MySQL Lim(int limit)
        {
            this.limit = limit;
            return this;
        }
        // 一种快捷方式,用于设置WHERE条件为根据ID字段来筛选某一条特定记录,返回当前MySQL类实例,方便继续链式调用
        public MySQL ID(int id)
        {
            whereClause = $"ID={id}";
            return this;
        }
        // 获取数据库连接对象的方法,直接返回已创建的连接对象(在构造函数中已创建长连接)
        private MySqlConnection GetConnection()
        {
            return connection;
        }
        // 根据列名列表构建查询语句中的列选择子句,如果列列表为空则返回 * 表示选择所有列
        private string GetColumnsClause()
        {
            if (columns.Count == 0)
            {
                return "*";
            }
            return string.Join(",", columns);
        }
        // 根据设置的排序字段和排序顺序(升序或降序)构建ORDER BY子句,用于查询语句中
        private string GetOrderByClause()
        {
            if (orderByColumn != null)
            {
                string orderBy = orderByColumn;
                if (orderByDescending)
                {
                    orderBy += " DESC";
                }
                return $"ORDER BY {orderBy}";
            }
            return "";
        }
        // 根据设置的限制数量构建LIMIT子句,用于查询语句中
        private string GetLimitClause()
        {
            if (limit > 0)
            {
                return $"LIMIT {limit}";
            }
            return "";
        }
        // 综合前面的列选择、WHERE条件、排序和限制等信息,构建完整的SELECT查询语句
        private string GetSelectQuery()
        {
            string columnsClause = GetColumnsClause();
            string where = whereClause != null ? $"WHERE {whereClause}" : "";
            string orderBy = GetOrderByClause();
            string limit = GetLimitClause();

            return $"SELECT {columnsClause} FROM {tableName} {where} {orderBy} {limit}";
        }
        // 执行查询并返回包含所有符合条件的数据的DataTable对象,用于获取多条查询结果
        public DataTable All()
        {
            try
            {
                using (MySqlConnection connection = GetConnection())
                {
                    if (connection.State != ConnectionState.Open)
                    {
                        connection.Open();
                    }
                    string query = GetSelectQuery();
                    using (MySqlCommand command = new MySqlCommand(query, connection))
                    {
                        using (MySqlDataAdapter adapter = new MySqlDataAdapter(command))
                        {
                            DataTable dataTable = new DataTable();
                            adapter.Fill(dataTable);
                            return dataTable;
                        }
                    }
                }
            }
            catch (MySqlException ex)
            {
                LogError($"查询数据失败(All方法): {ex.Message}");
                throw new DatabaseOperationException("查询数据失败", ex);
            }
        }
        // 异步版本
        public async Task<DataTable> AllAsync(CancellationToken cancellationToken = default)
        {
            try
            {
                using (MySqlConnection connection = GetConnection())
                {
                    if (connection.State != ConnectionState.Open)
                    {
                        await connection.OpenAsync(cancellationToken);
                    }
                    string query = GetSelectQuery();
                    using (MySqlCommand command = new MySqlCommand(query, connection))
                    {
                        using (MySqlDataAdapter adapter = new MySqlDataAdapter(command))
                        {
                            DataTable dataTable = new DataTable();
                            await Task.Run(() => adapter.Fill(dataTable), cancellationToken);
                            return dataTable;
                        }
                    }
                }
            }
            catch (MySqlException ex)
            {
                LogError($"异步查询数据失败(AllAsync方法): {ex.Message}");
                throw new DatabaseOperationException("异步查询数据失败", ex);
            }
        }
        // 执行查询并返回符合条件的第一条数据(如果有),以DataRow对象形式返回,用于获取单条查询结果
        public DataRow One()
        {
            try
            {
                using (MySqlConnection connection = GetConnection())
                {
                    if (connection.State != ConnectionState.Open)
                    {
                        connection.Open();
                    }
                    string query = GetSelectQuery() + " LIMIT 1";
                    using (MySqlCommand command = new MySqlCommand(query, connection))
                    {
                        using (MySqlDataReader reader = command.ExecuteReader())
                        {
                            if (reader.Read())
                            {
                                DataTable dataTable = new DataTable();
                                DataTable schemaTable = reader.GetSchemaTable();
                                DataRow row = dataTable.NewRow();
                                for (int i = 0; i < schemaTable.Rows.Count; i++)
                                {
                                    row[schemaTable.Rows[i]["ColumnName"].ToString()??string.Empty] = reader[schemaTable.Rows[i]["ColumnName"].ToString()];
                                }
                                return row;
                            }
                            return default;
                        }
                    }
                }
            }
            catch (MySqlException ex)
            {
                LogError($"查询数据失败(One方法): {ex.Message}");
                throw new DatabaseOperationException("查询数据失败", ex);
            }
        }
        // 插入数据方法,接收一个字典,键为要插入的列名,值为对应列要插入的值,执行插入操作后返回受影响的行数
        public int Insert(Dictionary<string, object> values)
        {
            try
            {
                using (MySqlConnection connection = GetConnection())
                {
                    if (connection.State != ConnectionState.Open)
                    {
                        connection.Open();
                    }
                    string columnsStr = string.Join(",", values.Keys);
                    string valuesStr = string.Join(",", values.Keys.Select(key => $"@{key}"));
                    string query = $"INSERT INTO {tableName} ({columnsStr}) VALUES ({valuesStr})";
                    using (MySqlCommand command = new MySqlCommand(query, connection))
                    {
                        foreach (var pair in values)
                        {
                            command.Parameters.AddWithValue($"@{pair.Key}", pair.Value);
                        }
                        return command.ExecuteNonQuery();
                    }
                }
            }
            catch (MySqlException ex)
            {
                LogError($"插入数据失败: {ex.Message}");
                throw new DatabaseOperationException("插入数据失败", ex);
            }
        }
        // 更新数据方法,接收一个字典,键为要更新的列名,值为对应列要更新的值,执行更新操作后返回受影响的行数
        public int Update(Dictionary<string, object> values)
        {
            try
            {
                using (MySqlConnection connection = GetConnection())
                {
                    if (connection.State != ConnectionState.Open)
                    {
                        connection.Open();
                    }
                    List<string> setClauses = new List<string>();
                    foreach (var pair in values)
                    {
                        setClauses.Add($"{pair.Key}=@{pair.Key}");
                    }
                    string setClause = string.Join(",", setClauses);
                    string query = $"UPDATE {tableName} SET {setClause} {whereClause}";
                    using (MySqlCommand command = new MySqlCommand(query, connection))
                    {
                        foreach (var pair in values)
                        {
                            command.Parameters.AddWithValue($"@{pair.Key}", pair.Value);
                        }
                        return command.ExecuteNonQuery();
                    }
                }
            }
            catch (MySqlException ex)
            {
                LogError($"更新数据失败: {ex.Message}");
                throw new DatabaseOperationException("更新数据失败", ex);
            }
        }
        // 删除数据方法,根据之前设置的WHERE条件(如果有)构建DELETE语句,执行删除操作后返回受影响的行数
        public int Delete()
        {
            try
            {
                using (MySqlConnection connection = GetConnection())
                {
                    if (connection.State != ConnectionState.Open)
                    {
                        connection.Open();
                    }
                    string query = $"DELETE FROM {tableName} {whereClause}";
                    using (MySqlCommand command = new MySqlCommand(query, connection))
                    {
                        return command.ExecuteNonQuery();
                    }
                }
            }
            catch (MySqlException ex)
            {
                LogError($"删除数据失败: {ex.Message}");
                throw new DatabaseOperationException("删除数据失败", ex);
            }
        }
        // 关闭数据库连接方法,判断连接对象是否存在且处于打开状态,如果是则关闭连接,释放数据库连接资源
        public void Close()
        {
            try
            {
                if (connection != null && connection.State != ConnectionState.Closed)
                {
                    connection.Close();
                }
            }
            catch (MySqlException ex)
            {
                LogError($"关闭数据库连接失败: {ex.Message}");
                throw;
            }
        }
        // 日志记录方法
        private void LogError(string message)
        {
            // 这里可以扩展为写入文件、数据库或发送到日志服务
            Console.WriteLine($"[{DateTime.Now:yyyy-MM-dd HH:mm:ss}] ERROR: {message}");
        }

        // 执行自定义数据库指令方法,接收一个自定义的SQL语句字符串作为参数,打开数据库连接后执行该语句,返回受影响的行数
        public int Query(string sql)
        {
            try
            {
                using (MySqlConnection connection = GetConnection())
                {
                    if (connection.State != ConnectionState.Open)
                    {
                        connection.Open();
                    }
                    // 使用参数化查询防止SQL注入
                    using (MySqlCommand command = new MySqlCommand(sql, connection))
                    {
                        return command.ExecuteNonQuery();
                    }
                }
            }
            catch (MySqlException ex)
            {
                LogError($"执行自定义指令失败: {ex.Message}");
                throw new DatabaseOperationException("执行自定义指令失败", ex);
            }
        }
        // 新增:事务处理方法
        public void ExecuteTransaction(Action<MySqlTransaction> action)
        {
            using (MySqlConnection connection = GetConnection())
            {
                if (connection.State != ConnectionState.Open)
                {
                    connection.Open();
                }
                using (var transaction = connection.BeginTransaction())
                {
                    try
                    {
                        action(transaction);
                        transaction.Commit();
                    }
                    catch (Exception ex)
                    {
                        transaction.Rollback();
                        LogError($"事务执行失败: {ex.Message}");
                        throw new DatabaseOperationException("事务执行失败", ex);
                    }
                }
            }
        }
        // 新增:批量插入方法
        public int BulkInsert(List<Dictionary<string, object>> dataList)
        {
            if (dataList == null || !dataList.Any())
                return 0;

            using (MySqlConnection connection = GetConnection())
            {
                if (connection.State != ConnectionState.Open)
                {
                    connection.Open();
                }
                using (var transaction = connection.BeginTransaction())
                {
                    try
                    {
                        int affectedRows = 0;
                        string columnsStr = string.Join(",", dataList[0].Keys);
                        string valuesStr = string.Join(",", dataList[0].Keys.Select(key => $"@{key}"));

                        foreach (var values in dataList)
                        {
                            string query = $"INSERT INTO {tableName} ({columnsStr}) VALUES ({valuesStr})";
                            using (MySqlCommand command = new MySqlCommand(query, connection, transaction))
                            {
                                foreach (var pair in values)
                                {
                                    command.Parameters.AddWithValue($"@{pair.Key}", pair.Value);
                                }
                                affectedRows += command.ExecuteNonQuery();
                            }
                        }
                        transaction.Commit();
                        return affectedRows;
                    }
                    catch (Exception ex)
                    {
                        transaction.Rollback();
                        LogError($"批量插入失败: {ex.Message}");
                        throw new DatabaseOperationException("批量插入失败", ex);
                    }
                }
            }
        }
    }
}