2025-03-28 09:49:56 +08:00

282 lines
12 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
namespace RFIDServicePlate
{
public class MySQLInstallHelper
{
/// <summary>
/// 数据库安装运行状态
/// </summary>
public enum RunState
{
Error,
Running,
Finish,
Display,
NoDisplay
}
/// <summary>
/// 数据库安装委托事件
/// </summary>
/// <param name="resultString">运行信息</param>
/// <param name="runingState">运行状态</param>
public delegate void DataReceivedEvent(string resultString, RunState runState);
public event DataReceivedEvent DataReceivedEventClick;
public MySQLInstallHelper()
{
}
/// <summary>
/// 安装MySQL数据库
/// </summary>
/// <remarks>
/// 使用默认数据库服务名称MySQL
/// 使用默认数据库服务端口3306
/// </remarks>
public void StartMySQLInstall()
{
StartMySQLInstall("MySQL");
}
/// <summary>
/// 安装MySQL数据库
/// </summary>
/// <param name="serviceName">数据库服务名称</param>
/// <remarks>
/// 使用默认数据库服务端口3306
/// </remarks>
public void StartMySQLInstall(string serviceName)
{
StartMySQLInstall(serviceName, 3306);
}
/// <summary>
/// 使用指定服务名称安装MySQL数据库
/// </summary>
/// <param name="serviceName">数据库服务名称</param>
/// <param name="servicePort">数据库服务端口</param>
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);
}
/// <summary>
/// 运行程序并输出执行结果
/// </summary>
/// <param name="exeFile">需要运行的程序文件</param>
/// <param name="command">程序运行参数</param>
private void Shell(string exeFile, string command)
{
Shell(exeFile, command, string.Empty);
}
/// <summary>
/// 运行程序并输出执行结果
/// </summary>
/// <param name="exeFile">需要运行的程序文件</param>
/// <param name="command">程序运行参数</param>
/// <param name="workingDir">程序工作目录</param>
private void Shell(string exeFile, string command, string workingDir)
{
Shell(exeFile, command, workingDir, 0);
}
/// <summary>
/// 运行程序并输出执行结果
/// </summary>
/// <param name="exeFile">需要运行的程序文件</param>
/// <param name="command">程序运行参数</param>
/// <param name="workingDir">程序工作目录</param>
/// <param name="timeout">超时等待时间</param>
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();
}
}
}
/// <summary>
/// 打开控制台执行拼接完成的批处理命令字符串
/// </summary>
/// <param name="inputAction">需要执行的命令委托方法:每次调用 <paramref name="inputAction"/> 中的参数都会执行一次</param>
private void ExecBatCommand(Action<Action<string>> 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();
}
}
}
}