美文网首页csharp
[教程] C# 修改 max_allowed_packet 不生

[教程] C# 修改 max_allowed_packet 不生

作者: 雨落随风 | 来源:发表于2024-10-25 13:51 被阅读0次

问题描述

MySQL 默认 Max_Allowed_Packet 约为 4MB, 当我导入一个 19MB 左右的 .sql 文件时报错,错误如下:

System.ArgumentException: Option not supported. (Parameter 'max_allowed_packet')
   at MySql.Data.MySqlClient.MySqlConnectionStringBuilder.GetOption(String key)
   at MySql.Data.MySqlClient.MySqlConnectionStringBuilder.set_Item(String keyword, Object value)
   at System.Data.Common.DbConnectionStringBuilder.set_ConnectionString(String value)

通过执行 SET GLOBAL max_allowed_packet=20000000; 后依旧是初始值,但是下次启动程序却发现修改又成功了。

问题解答

经过不懈努力,寻求并整理得到以下 3 个结论:

  1. MySQL 在同一个 mysql 实例(同一个 Connection)中 使用SET GLOBAL max_allowed_packet=20000000; 修改了 paket size 在当前的 Connection 中无效,只有在下个 mysql 连接中生效
  2. MySQLConnect 通过依次调用 Close 、 Open 实现的 Connect 重连无法实现修改生效
  3. 通过SET GLOBAL max_allowed_packet=20000000; 修改了 paket size 在下次重启 MySql Service 后失效。(这是我的预期,我只希望临时生效)

解决方案:

问题都找到且失效原因都明确后,我找到了 2 个解决方案,但不管怎么说就是一个核心思路:保证在连接数据库前开一个新的进程来修改 max_allowed_packet , 随着进程的消亡,mysql 实例和连接释放,下个 Connection(也就是我们的 Connection)必然会生效。

方案一

在使用 MySQLConnection 连接前先调用 mysql.exe 设置一下 max_allowed_packet 的值,具体逻辑如下:

// 调用逻辑
public void Foo()
{
  var sqlFile = your .sql  file path here;
  ModifyMaxAllowedPacket(sqlFile);
// 这里开始你的连接
   var connStr = $"server={your IP};port={your Port};user={your User};password={your psw};charset=utf8";
   using var conn = new MySqlConnection(connStr);
    conn.Open();
// 这里开始你的 .sql  文件的导入
    var sql = File.ReadAllText(sqlFile);
    using (var importCmd = new MySqlCommand(sql, conn))
    {
        importCmd.CommandTimeout = 0;
        var result = importCmd.ExecuteNonQuery();
        Console.WriteLine($"执行 {sqlFile} 完毕,数据库新增数据 {result} 笔!");
    }    
  }

// 使用 mysql.exe 修改 max allowed packet
    private void ModifyMaxAllowedPacket(string sqlFile,string password)
    {
        var fileinfo = new FileInfo(sqlFile);
        try
        {
            // 通过 mysql.ServiceName 服务属性获取 mysql 的安装路径
            // 默认服务名称是: MySQL56
            if (serviceHandler.IsExistsService("MySQL56")) 
            {
                var mysqlPath = GetServiceExecPath(mysql.ServiceName);
                var pattern = @"^""(.*\\bin)\\.*$";
                var match = Regex.Match(mysqlPath, pattern);
                if (match.Success)
                {
                    var mysql_file = Path.Combine(match.Groups[1].Value, "mysql.exe");
                    if (!File.Exists(mysql_file))
                    {
                        throw new FileNotFoundException("未找到 mysql.exe 文件!");
                    }
// 请根据实际情况编写,另密码与-p之间没有空格
                    var args = @$"-u root -p{password} -h 127.0.0.1 -P 3306";
                    var process = new Process
                    {
                        StartInfo = new ProcessStartInfo
                        {
                            FileName = mysql_file,
                            Arguments = args,
                            UseShellExecute = false,
                            RedirectStandardInput = true,
                            CreateNoWindow = true
                        }
                    };
                    process.Start();
// 设置 max_allowed_packet 
                    process.StandardInput.WriteLine($"SET GLOBAL max_allowed_packet={fileinfo.Length * 2};");
// 退出 mysql 
                    process.StandardInput.WriteLine("exit");
                    process.WaitForExit();
                }
                 Console.WriteLine($"执行 SizeModifier 完成!");
            }
            else
            {
                throw new Exception($"未发现 {mysql.ServiceName} 服务,无法修改 max_allowed_packet!");
            }
        }
        catch (Exception ex)
        {
            Console.WriteLine($"Error: {ex.Message}");
        }
    }
    public string GetServiceExecPath(string serviceName)
    {
        string key = $@"SYSTEM\CurrentControlSet\Services\{serviceName}";
        using (RegistryKey serviceKey = Registry.LocalMachine.OpenSubKey(key))
        {
            if (serviceKey == null)
            {
                throw new Exception($"Service {serviceName} does not exist.");
            }
            return serviceKey.GetValue("ImagePath").ToString();
        }
    }

方案二

写一个控制台程序 MySQLMaxPackageSizeModifier 实现对 max_allowed_packet 的修改,在使用 MySQLConnection 连接前先调用这个控制台程序设置一下 max_allowed_packet 的值,具体逻辑如下:

MySQLMaxPackageSizeModifier.exe 调用逻辑:

// Usage: MySQLMaxPackageSizeModifier <server> <port> <user> <password> <max_allowed_packet>
// 本程序会使用传入的 user + psw 连接并修改 max allowed packet 的值为传入值(如果大于当前值)
// 程序执行完毕后,会自动关闭。

 var maxPacket = 1024 * 1024 * 1024; // 1G
 var maxPacketModifier = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "MySQLMaxPackageSizeModifier.exe");
 var args = $"{mysql.IP} {mysql.Port} {mysql.User} {password} {maxPacket}";
 var process = new Process
 {
     StartInfo = new ProcessStartInfo
     {
         FileName = maxPacketModifier,
         Arguments = args,
         UseShellExecute = false,
         RedirectStandardOutput = true,
         CreateNoWindow = true
     }
 };
 process.Start();
 process.WaitForExit();
 var message = process.StandardOutput.ReadToEnd().Trim();
 Console.WriteLine($"执行 SizeModifier 完成!返回了:{message}");

// 接下来正式开始你的 MySQLConnection 的连接和数据的写入逻辑

MySQLMaxPackageSizeModifier 的实现:

using MySql.Data.MySqlClient;

class Program
{
    static void Main(string[] args)
    {
        if (args.Length < 5)
        {
            Console.WriteLine("Usage: MySQLMaxPackageSizeModifier <server> <port> <user> <password> <max_allowed_packet>");
            return;
        }

        string server = args[0];
        string port = args[1];
        string user = args[2];
        string password = args[3];
        int maxAllowedPacket = int.Parse(args[4]);

        string connStr = $"server={server};port={port};user={user};password={password};charset=utf8";

        try
        {
            using (var conn = new MySqlConnection(connStr))
            {
                conn.Open();
                // 先查询当前 max_allowed_packet 的值
                var currentMaxAllowedPacket = 0;
                var sql = "SHOW VARIABLES LIKE 'max_allowed_packet';";
                using (var cmd = new MySqlCommand(sql, conn))
                {
                    using var reader = cmd.ExecuteReader();
                    if (reader.Read()) // 读取结果集中的第一行
                    {
                        // Value 列是第二列,索引为 1
                        var maxValue = reader.GetString(1);
                        currentMaxAllowedPacket = int.Parse(maxValue);
                    }
                }
                if (currentMaxAllowedPacket < maxAllowedPacket)
                {
                    string setMaxAllowedPacketQuery = $"SET GLOBAL max_allowed_packet={maxAllowedPacket};";
                    using (var cmd = new MySqlCommand(setMaxAllowedPacketQuery, conn))
                    {
                        cmd.ExecuteNonQuery();
                    }
                    Console.WriteLine($"Successfully set max_allowed_packet to {maxAllowedPacket}.");
                }
            }
        }
        catch (Exception ex)
        {
            Console.WriteLine($"Error: {ex.Message}");
        }
    }
}

写到最后

我最先实现的是本文第二种解决方案,但是由于需要自己再多维护一个程序,属实不优雅;因此使用了本文第一种方法,通过 MySQL 服务定位、运行并设置 Packet 后全身而退,Prefect!

扩展阅读

  1. 为什么修改 packet size 后不能立刻生效?
  2. 怎么通过 MySQL 服务定位 mysql.exe 安装路径?
  3. 如何通过修改 my.ini 配置实现对 packet size 的永久修改
  4. MySQL 官方 packet-too-large 相关

Tips:使用 SHOW VARIABLES LIKE 'max_allowed_packet'; 可以查询当前 packet size 的设置值。

笔者原创,版权所有,转载请注明出处!

相关文章

  • C#入门教程(二)–C#常用快捷键、变量、类型转换-打造C#

    C#入门教程(一)–.Net平台技术介绍、C#语言及开发工具介绍-打造C#学习教程 上次教程主要介绍了.Net平台...

  • Winform

    C# WinForm实践开发教程 C# WinForm实践开发教程——第一章 Windows编程基础C# WinF...

  • 修改max_allowed_packet

    show variables like '%max_allowed%'; set global max_allow...

  • 黑马训练营Asp.Net第2期完整版

    初级 .Net入门教程_.Net入门视频教程|黑马程序员 C#基础教程_C#基础视频教程_黑马程序员 .Net基础...

  • Mysql导入sql文件过大问题解决

    方案一:修改Mysql配置 默认情况下,MySQL的最大允许包(max_allowed_packet)是10485...

  • Mysql修改max_allowed_packet参数

    写入或读取MySQL报错超出 max_allowed_packet 的问题。 如果出现上图提示的错误,就需要修改 ...

  • 真会 C# 吗 03

    声明 本文内容来自微软 MVP solenovex 的视频教程——真会C#吗?-- C#全面教程,大致和第 6 课...

  • 真会 C# 吗 04

    声明 本文内容来自微软 MVP solenovex 的视频教程——真会C#吗?-- C#全面教程,大致和第 7 课...

  • 真会 C# 吗 02

    声明 本文内容来自微软 MVP solenovex 的视频教程——真会C#吗?-- C#全面教程,大致和第 5 课...

  • 真会 C# 吗 05

    声明 本文内容来自微软 MVP solenovex 的视频教程——真会C#吗?-- C#全面教程,大致和第 8 课...

网友评论

    本文标题:[教程] C# 修改 max_allowed_packet 不生

    本文链接:https://www.haomeiwen.com/subject/gfksdjtx.html