282 lines
12 KiB
C#
282 lines
12 KiB
C#
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();
|
||
}
|
||
}
|
||
}
|
||
}
|