using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Text; namespace RFIDServicePlate { public class MySQLInstallHelper { /// /// 数据库安装运行状态 /// public enum RunState { Error, Running, Finish, Display, NoDisplay } /// /// 数据库安装委托事件 /// /// 运行信息 /// 运行状态 public delegate void DataReceivedEvent(string resultString, RunState runState); public event DataReceivedEvent DataReceivedEventClick; public MySQLInstallHelper() { } /// /// 安装MySQL数据库 /// /// /// 使用默认数据库服务名称:MySQL /// 使用默认数据库服务端口:3306 /// public void StartMySQLInstall() { StartMySQLInstall("MySQL"); } /// /// 安装MySQL数据库 /// /// 数据库服务名称 /// /// 使用默认数据库服务端口:3306 /// public void StartMySQLInstall(string serviceName) { StartMySQLInstall(serviceName, 3306); } /// /// 使用指定服务名称安装MySQL数据库 /// /// 数据库服务名称 /// 数据库服务端口 public void StartMySQLInstall(string serviceName, int servicePort) { if (string.IsNullOrWhiteSpace(serviceName)) { DataReceivedEventClick?.Invoke("安装失败:数据库服务名称不能为空。", RunState.Error); return; } string str_BaseDirectory = AppDomain.CurrentDomain.BaseDirectory; //判断服务端口是否在有效范围 if (servicePort < 1 || servicePort > 65535) { //无效端口时,改为使用默认端口 servicePort = 3306; } //判断数据库服务是否已存在 //if (ESSupport.Lib.WindowsServiceHelper.IsServiceIsExisted(serviceName)) // { //停止正在运行的服务 DataReceivedEventClick?.Invoke($"正在停止{serviceName}服务", RunState.Running); Shell("net.exe", $"stop {serviceName}"); //移除已安装的MySQL服务 DataReceivedEventClick?.Invoke($"正在删除{serviceName}服务", RunState.Running); ExecBatCommand(p => { p($".\\bin\\mysqld remove {serviceName}"); p("exit 0"); }, str_BaseDirectory); // } //根据操作系统位数安装MySQL8.0运行所需的VC++2019运行库 DataReceivedEventClick?.Invoke("正在安装程序运行库...", RunState.Running); if (Environment.Is64BitOperatingSystem) { Shell("VC2019_x64.exe", "/install /q /norestart"); } else { Shell("VC2019_x86.exe", "/install /q /norestart"); } if (!File.Exists(Path.Combine(str_BaseDirectory, "my.ini"))) { //创建MySQL数据库配置文件 DataReceivedEventClick?.Invoke("正在创建数据库配置文件...", RunState.Running); //MySQL数据库服务端口 ESSupport.Lib.Win32API.INIWriteValue(Path.Combine(str_BaseDirectory, "my.ini"), "mysqld", "port", servicePort.ToString()); //MySQL数据库安装目录 ESSupport.Lib.Win32API.INIWriteValue(Path.Combine(str_BaseDirectory, "my.ini"), "mysqld", "basedir", str_BaseDirectory); //MySQL数据库文件目录 ESSupport.Lib.Win32API.INIWriteValue(Path.Combine(str_BaseDirectory, "my.ini"), "mysqld", "datadir", Path.Combine(str_BaseDirectory, "Data")); //允许的最大连接数 ESSupport.Lib.Win32API.INIWriteValue(Path.Combine(str_BaseDirectory, "my.ini"), "mysqld", "max_connections", "200"); //MySQL服务端使用的默认字符集 ESSupport.Lib.Win32API.INIWriteValue(Path.Combine(str_BaseDirectory, "my.ini"), "mysqld", "character-set-server", "utf8mb4"); //创建新表时将使用的默认存储引擎 ESSupport.Lib.Win32API.INIWriteValue(Path.Combine(str_BaseDirectory, "my.ini"), "mysqld", "default-storage-engine", "INNODB"); //数据库用户密码默认的加密方式 ESSupport.Lib.Win32API.INIWriteValue(Path.Combine(str_BaseDirectory, "my.ini"), "mysqld", "default_authentication_plugin ", "mysql_native_password"); //MySQL客户端使用的默认字符集 ESSupport.Lib.Win32API.INIWriteValue(Path.Combine(str_BaseDirectory, "my.ini"), "mysql", "default-character-set ", "utf8mb4"); //客户端连接使用的默认端口 ESSupport.Lib.Win32API.INIWriteValue(Path.Combine(str_BaseDirectory, "my.ini"), "client", "port", servicePort.ToString()); } DataReceivedEventClick?.Invoke("正在初始化数据库...", RunState.Running); if (!Directory.Exists(Path.Combine(str_BaseDirectory, "Data"))) { Directory.CreateDirectory(Path.Combine(str_BaseDirectory, "Data")); } ExecBatCommand(p => { p(".\\bin\\mysqld --initialize-insecure --user=mysql"); p("exit 0"); }, str_BaseDirectory); DataReceivedEventClick?.Invoke("正在安装数据库服务...", RunState.Running); ExecBatCommand(p => { p($".\\bin\\mysqld install {serviceName} --defaults-file=\"{Path.Combine(str_BaseDirectory, "my.ini")}\""); p("exit 0"); }, str_BaseDirectory); File.WriteAllLines(Path.Combine(str_BaseDirectory, "dba.sql"), new string[] { "ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY 'yskj2020';", "FLUSH PRIVILEGES;" }); DataReceivedEventClick?.Invoke("正在启动数据库服务...", RunState.Running); Shell("net.exe", $"start {serviceName}"); DataReceivedEventClick?.Invoke("正在设置数据库密码...", RunState.Running); ExecBatCommand(p => { p(".\\bin\\mysqladmin -u root password \"yskj2020\""); p($".\\bin\\mysql -u root -pyskj2020 <\"{Path.Combine(str_BaseDirectory, "dba.sql")}\""); p($"%WINDIR%\\SYSTEM32\\setx MYSQL_HOME \"{str_BaseDirectory}\" /M"); p("exit 0"); }, str_BaseDirectory); if (File.Exists(Path.Combine(str_BaseDirectory, "dba.sql"))) { File.Delete(Path.Combine(str_BaseDirectory, "dba.sql")); } DataReceivedEventClick?.Invoke("运行结束", RunState.Finish); } /// /// 运行程序并输出执行结果 /// /// 需要运行的程序文件 /// 程序运行参数 private void Shell(string exeFile, string command) { Shell(exeFile, command, string.Empty); } /// /// 运行程序并输出执行结果 /// /// 需要运行的程序文件 /// 程序运行参数 /// 程序工作目录 private void Shell(string exeFile, string command, string workingDir) { Shell(exeFile, command, workingDir, 0); } /// /// 运行程序并输出执行结果 /// /// 需要运行的程序文件 /// 程序运行参数 /// 程序工作目录 /// 超时等待时间 private void Shell(string exeFile, string command, string workingDir, int timeout) { System.Diagnostics.Process process = null; try { process = new System.Diagnostics.Process(); process.StartInfo.FileName = exeFile; //设置要启动的应用程序,如:fastboot process.StartInfo.Arguments = command; // 设置应用程序参数,如: flash boot0 "A_Debug/boot0.img" process.StartInfo.UseShellExecute = false; process.StartInfo.RedirectStandardInput = true; process.StartInfo.RedirectStandardOutput = true; process.StartInfo.RedirectStandardError = true; process.StartInfo.CreateNoWindow = true; process.EnableRaisingEvents = true; // 获取或设置在进程终止时是否应激发 Exited 事件;不论是正常退出还是异常退出。 if (!string.IsNullOrWhiteSpace(workingDir)) { process.StartInfo.WorkingDirectory = workingDir; // **重点**,工作目录,必须是 bat 批处理文件所在的目录 } process.OutputDataReceived += (sender, e) => DataReceivedEventClick?.Invoke(e.Data, RunState.Running); process.ErrorDataReceived += (sender, e) => DataReceivedEventClick?.Invoke(e.Data, RunState.Running); process.Start(); process.BeginOutputReadLine(); // 开启异步读取输出操作 process.BeginErrorReadLine(); // 开启异步读取错误操作 if (timeout > 0) { process.WaitForExit(timeout); } else { process.WaitForExit(); } } finally { if (process != null && !process.HasExited) { process.Kill(); } if (process != null) { process.Close(); } } } /// /// 打开控制台执行拼接完成的批处理命令字符串 /// /// 需要执行的命令委托方法:每次调用 中的参数都会执行一次 private void ExecBatCommand(Action> inputAction, string workingDir) { System.Diagnostics.Process pro = null; System.IO.StreamWriter sIn = null; System.IO.StreamReader sOut = null; try { pro = new System.Diagnostics.Process(); pro.StartInfo.FileName = "cmd.exe"; pro.StartInfo.UseShellExecute = false; pro.StartInfo.CreateNoWindow = true; pro.StartInfo.RedirectStandardInput = true; pro.StartInfo.RedirectStandardOutput = true; pro.StartInfo.RedirectStandardError = true; if (!string.IsNullOrWhiteSpace(workingDir)) { pro.StartInfo.WorkingDirectory = workingDir; // **重点**,工作目录,必须是 bat 批处理文件所在的目录 } //pro.OutputDataReceived += (sender, e) => DataReceivedEventClick?.Invoke(e.Data, RunState.Running); //pro.ErrorDataReceived += (sender, e) => DataReceivedEventClick?.Invoke(e.Data, RunState.Running); pro.Start(); sIn = pro.StandardInput; sIn.AutoFlush = true; pro.BeginOutputReadLine(); inputAction(value => sIn.WriteLine(value)); pro.WaitForExit(); } finally { if (pro != null && !pro.HasExited) pro.Kill(); if (sIn != null) sIn.Close(); if (sOut != null) sOut.Close(); if (pro != null) pro.Close(); } } } }