bat脚本安装MySQL

bat脚本安装MySQL,注册Windows服务,设置root密码,新增用户,并执行脚本。此处用的MySQL5.7的压缩包版本。将MySQL移动到C:\ProgramData目录下,进行安装。

@echo off
setlocal enabledelayedexpansion

REM ====== 可配置参数 ======


set TARGET_PARENT=C:\ProgramData
set BASE_DIR=%TARGET_PARENT%\mysql_57


set INSTALL_DIR=%BASE_DIR%\mysql-5.7.44-winx64
set DATA_DIR=%INSTALL_DIR%\data
set MYSQL_SERVICE_NAME=MySQL57
set MYSQL_PORT=3306

set ROOT_PASSWORD=root
set APP_USER=user1
set APP_PASSWORD=userpwd

REM =========================


echo =====================================================
echo MySQL 5.7 Auto Install Script
echo =====================================================

REM ====== 1. 检测服务是否已存在 ======
echo Checking existing MySQL service...

sc query %MYSQL_SERVICE_NAME% >nul 2>&1
if %errorlevel% EQU 0 (
echo MySQL service "%MYSQL_SERVICE_NAME%" already exists.
echo Installation aborted to prevent overwrite.
exit /b 0
)


REM ====== 2. 检测系统中是否已有其他 MySQL 服务 ======
set "OTHER_MYSQL_FOUND="

REM 使用 tokens=2 抓取冒号后的实际名称,并过滤掉我们自己定义的服务名
for /f "tokens=2" %%s in ('sc query state^= all ^| findstr /I "SERVICE_NAME" ^| findstr /I "MySQL"') do (
    set "TEMP_SERVICE=%%s"
    if /I "!TEMP_SERVICE!" NEQ "%MYSQL_SERVICE_NAME%" (
        set "OTHER_MYSQL_FOUND=!TEMP_SERVICE!"
    )
)

if defined OTHER_MYSQL_FOUND (
    echo [ERROR] Another MySQL service detected: !OTHER_MYSQL_FOUND!
    echo Installation aborted.
    pause
    exit /b 0
)


REM ====== 3. 检测端口是否被占用 ======
echo Checking port %MYSQL_PORT%...

netstat -ano | findstr ":%MYSQL_PORT% " >nul
if %errorlevel% EQU 0 (
echo Port %MYSQL_PORT% is already in use.
echo Installation aborted.
exit /b 0
)




REM ====== 4. 目录迁移逻辑 (处理路径中的括号问题) ======
REM 使用引号包裹路径,防止 (x86) 导致脚本崩溃
set "CURRENT_DIR=%~dp0"
if /I "%CURRENT_DIR%" NEQ "%BASE_DIR%\" (
    echo Moving files to %BASE_DIR%...
    
    if not exist "%TARGET_PARENT%" mkdir "%TARGET_PARENT%"
    
    REM 复制当前目录到 ProgramData
    xcopy "%~dp0*" "%BASE_DIR%\" /E /I /Y /Q >nul
    
    if !errorlevel! EQU 0 (
        echo Files moved successfully. Relaunching...
        REM 关键:使用 pushd 切换环境,避免旧路径括号干扰
        pushd "%BASE_DIR%"
        start "" /D "%BASE_DIR%" "%BASE_DIR%\%~nx0"
        exit /b 0
    ) else (
        echo [ERROR] Failed to move files. Please run as Administrator.
        pause & exit /b 1
    )
)


echo ==== Creating my.ini ====

(
echo [mysqld]
echo basedir="%INSTALL_DIR%"
echo datadir="%DATA_DIR%"
echo port=%MYSQL_PORT%
echo character-set-server=utf8
echo default-storage-engine=INNODB
echo sql_mode=NO_ENGINE_SUBSTITUTION,STRICT_TRANS_TABLES
echo max_connections=200
echo ssl=0
echo.
echo [client]
echo default-character-set=utf8
) > "%INSTALL_DIR%\my.ini"

echo ==== Initializing database ====

"%INSTALL_DIR%\bin\mysqld.exe" ^
--initialize-insecure ^
--basedir="%INSTALL_DIR%" ^
--datadir="%DATA_DIR%"

if errorlevel 1 (
echo MySQL initialize FAILED
exit /b 1
)

echo ==== Installing Windows Service ====

"%INSTALL_DIR%\bin\mysqld.exe" ^
--install %MYSQL_SERVICE_NAME% ^
--defaults-file="%INSTALL_DIR%\my.ini"

sc config %MYSQL_SERVICE_NAME% start= auto >nul

echo ==== Starting Service ====
net start %MYSQL_SERVICE_NAME%

timeout /t 5 >nul

echo ==== Configuring Firewall ====

netsh advfirewall firewall show rule name="MySQL57 3306" >nul 2>&1
if %errorlevel% NEQ 0 (
    netsh advfirewall firewall add rule name="MySQL57 3306" dir=in action=allow protocol=TCP localport=%MYSQL_PORT%
    echo Firewall rule added
) else (
    echo Firewall rule already exists
)

echo ==== Setting root password ====

"%INSTALL_DIR%\bin\mysqladmin.exe" ^
-u root password "%ROOT_PASSWORD%"

echo ==== Creating user and privileges ====

"%INSTALL_DIR%\bin\mysql.exe" ^
-u root -p%ROOT_PASSWORD% ^
-e "CREATE USER '%APP_USER%'@'%%' IDENTIFIED BY '%APP_PASSWORD%';"

"%INSTALL_DIR%\bin\mysql.exe" ^
-u root -p%ROOT_PASSWORD% ^
-e "GRANT ALL PRIVILEGES ON *.* TO '%APP_USER%'@'%%' WITH GRANT OPTION; FLUSH PRIVILEGES;"

echo ==== Executing SQL scripts ====

"%INSTALL_DIR%\bin\mysql.exe" -u root -p%ROOT_PASSWORD% < "%BASE_DIR%\sql\init1.sql"

"%INSTALL_DIR%\bin\mysql.exe" -u root -p%ROOT_PASSWORD% < "%BASE_DIR%\sql\init2.sql"

echo ==== MySQL 5.7 Installed Successfully ====
exit /b 0

c#命名管道服务

代码如下:

private async Task CustomNamedPipeServer(CancellationToken token)
{
	while (!token.IsCancellationRequested)
	{
		try
		{
			var pipeServer = CreatePipeServer();

			await pipeServer.WaitForConnectionAsync(token)
							.ConfigureAwait(false);

			// 交给后台处理
			_ = HandleClientLongConnectionAsync(pipeServer, token);

			
		}
		catch (OperationCanceledException) { break; }
		catch (Exception ex)
		{
			logger.Error($"[CustomPipe Server Error] {ex.Message}");
			await Task.Delay(1000, token);
		}
	}
}

private NamedPipeServerStream CreatePipeServer()
{
	return new NamedPipeServerStream(
		"YourPipeName",
		PipeDirection.InOut,
		NamedPipeServerStream.MaxAllowedServerInstances,
		PipeTransmissionMode.Message,
		PipeOptions.Asynchronous,
		1024 * 32,
		1024 * 32);
}


private async Task HandleClientLongConnectionAsync(
            NamedPipeServerStream pipeServer,
            CancellationToken token)
{
	byte[] buffer = new byte[65536];
	var ms = new MemoryStream();
	try
	{

		using (var writer = new StreamWriter(pipeServer, new UTF8Encoding(false)) { AutoFlush = true })
		{
			while (!token.IsCancellationRequested &&
			   pipeServer.IsConnected)
			{
				int bytesReadLen = await pipeServer.ReadAsync(buffer, 0, buffer.Length, token);
				if (bytesReadLen == 0)
				{
					logger.Warn("收到空,客户端可能断开");
					break;
				}

				ms.Write(buffer, 0, bytesReadLen);

				if (!pipeServer.IsMessageComplete && pipeServer.TransmissionMode == PipeTransmissionMode.Message)
				{
					continue;
				}
				string msg = Encoding.UTF8.GetString(ms.ToArray());

				logger.Debug("收到数据:" + msg);
				ms.SetLength(0);	// 重置

				// 你的逻辑

					await writer.WriteLineAsync("ReceiveOK")
								.ConfigureAwait(false);
				}
			}
		}


	}
	catch (Exception ex)
	{
		
	}
	finally
	{
		try { pipeServer.Dispose(); } catch { }

		
	}
}

2. 调用

CancellationTokenSource _cts = new CancellationTokenSource();
Task _receTask = Task.Run(() => CustomNamedPipeServer(_cts.Token));

// 停止
_cts.Cancel();

winform中propertygrid可用的动态属性

  1. 动态对象
// 动态对象实现
    [TypeConverter(typeof(CategoriesSortedByClassDefinitionConverter)), CategoriesSortedByClassDefinitionConverter.ElementsSameOrder]
    public class DynamicObject : ICustomTypeDescriptor
    {
        /// <summary>
        /// 项目的英文名称
        /// </summary>
        public string CustomName { set; get; }
        public object TagInfo { get; set; }

        // private PropertyCollection _properties = new PropertyCollection();
        private List<DynamicProperty> _properties = new List<DynamicProperty>();
        private List<string> _categoryList = new List<string>();

        public void AddProperty(string name, object value, string displayName = null, string description = null, string cateogry = "属性", bool readOnly = false, Type converterType = null, bool browsable = true, TypeConverter typeConverter = null)
        {
            _properties.Add(new DynamicProperty(name, value, displayName, description, cateogry, readOnly, converterType, browsable, typeConverter));
            if (!string.IsNullOrEmpty(cateogry) && !_categoryList.Contains(cateogry))
            {
                _categoryList.Add(cateogry);
            }
        }

        public object GetPropertyOwner(PropertyDescriptor pd) => this;

        /// <summary>
        /// 返回属性的集合
        /// </summary>
        /// <returns></returns>
        public PropertyDescriptorCollection GetProperties()
        {
            /*var visibleProperties = _properties.Where(p => p.IsBrowsable);
            return new PropertyDescriptorCollection(visibleProperties.ToArray());*/

            //return new PropertyDescriptorCollection(_properties.ToArray(), true);

            var arr = _properties.Where(x => x.IsBrowsable).ToArray();
            return new PropertyDescriptorCollection(arr, true);
        }

        public PropertyDescriptorCollection GetProperties(Attribute[] attributes)
        {
            return GetProperties();
            //return new PropertyDescriptorCollection(_properties.ToArray());
        }

        // ICustomTypeDescriptor 其他接口方法可以选择实现空逻辑
        public AttributeCollection GetAttributes() => AttributeCollection.Empty;
        public string GetClassName() => null;
        public string GetComponentName() => null;
        public TypeConverter GetConverter() => null;
        public EventDescriptor GetDefaultEvent() => null;
        public PropertyDescriptor GetDefaultProperty() => null;
        public object GetEditor(Type editorBaseType) => null;
        public EventDescriptorCollection GetEvents() => EventDescriptorCollection.Empty;
        public EventDescriptorCollection GetEvents(Attribute[] attributes) => EventDescriptorCollection.Empty;

        public List<DynamicProperty> GetDynamicProperties() => _properties;

        public DynamicProperty GetDynamicProperty(string name)
        {
            if (string.IsNullOrEmpty(name))
            {
                return null;
            }

            DynamicProperty data = null;
            foreach (DynamicProperty tmp in _properties)
            {
                if (!tmp.Name.Equals(name))
                {
                    continue;
                }

                data = tmp;
                break;
            }

            return data;
        }

        public void SetPropertyReadonly(string name, bool isReadOnly)
        {
            foreach (var tmp in _properties)
            {
                if (!tmp.Name.Equals(name))
                {
                    continue;
                }

                tmp.CustomIsRreadOnly = isReadOnly;
                break;
            }
        }

        public void SetPropertyBrowse(string name, bool browse)
        {
            foreach (var tmp in _properties)
            {
                if (!tmp.Name.Equals(name))
                {
                    continue;
                }

                tmp.SetBrowse(browse);
                break;
            }
        }

        public void SetCustomConverter(string name, TypeConverter typeConverter)
        {
            foreach (var tmp in _properties)
            {
                if (!tmp.Name.Equals(name))
                {
                    continue;
                }

                tmp.CustomTypeConverter = typeConverter;
                break;
            }
        }

        public bool RemovePropertyByName(string name)
        {
            if (string.IsNullOrEmpty(name))
            {
                return true;
            }

            DynamicProperty data = null;

            foreach (DynamicProperty tmp in _properties)
            {
                if (!tmp.Name.Equals(name))
                {
                    continue;
                }

                data = tmp;
                break;
            }

            _properties.Remove(data);

            return true;
        }
    }

2. 动态属性

// 动态属性类
    public class DynamicProperty : PropertyDescriptor
    {
        private object _value;
        private Type _converterType;
        private string _displayName;
        private string _category;
        private bool _brows;
        private string _desc;
        private bool _readOnly;
        private TypeConverter _typeConverter;

        public bool CustomIsRreadOnly { set; get; }

        public TypeConverter CustomTypeConverter { get => _typeConverter; set { _typeConverter = value; } }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="name"></param>
        /// <param name="value"></param>
        /// <param name="displayName">显示名称</param>
        /// <param name="description">描述</param>
        /// <param name="cateogry">分类</param>
        /// <param name="readlyOnly">只读</param>
        /// <param name="converterType">转换器</param>
        /// <param name="brows">显示</param>
        public DynamicProperty(string name, object value, string displayName = null, string description = null, string cateogry = "属性", bool readlyOnly = false, Type converterType = null, bool brows = true, TypeConverter typeConverter = null) : base(name, new Attribute[0])
        {
            _value = value;
            _converterType = converterType;
            _displayName = displayName;
            if (string.IsNullOrEmpty(displayName))
            {
                _displayName = name;
            }
            _category = cateogry;
            _brows = brows;
            _desc = description;
            _readOnly = readlyOnly;
            CustomIsRreadOnly = readlyOnly;
            _typeConverter = typeConverter;
        }

        public override bool CanResetValue(object component) => false;
        public override Type ComponentType => typeof(DynamicObject);
        public override object GetValue(object component) => _value;
        public override bool IsReadOnly => CustomIsRreadOnly;
        public override Type PropertyType => _value.GetType();
        public override void ResetValue(object component) { }
        public override void SetValue(object component, object value) => _value = value;
        public override bool ShouldSerializeValue(object component) => true;

        public override TypeConverter Converter
        {
            get
            {
                /*if (_value is bool)
                {
                    return new BooleanCheckBoxConverter();
                }*/
                if (_converterType != null)
                {
                    return (TypeConverter)Activator.CreateInstance(_converterType);
                }
                if (_typeConverter != null)
                {
                    return _typeConverter;
                }
                return base.Converter;
            }
        }

        public override string DisplayName => _displayName;

        public override string Category => _category;

        public override bool IsBrowsable => _brows;

        public override string Description => _desc;


        public override AttributeCollection Attributes
        {
            get
            {
                var attributes = base.Attributes.Cast<Attribute>().ToList();
                if (CustomIsRreadOnly)
                {
                    attributes.Add(new ReadOnlyAttribute(true));
                }

                return new AttributeCollection(attributes.ToArray());
            }
        }

        public void SetCategory(string newCategory)
        {
            _category = newCategory;
        }

        public void SetBrowse(bool val)
        {
            _brows = val;
        }
    }

3. 用法

DynamicObject gradeObj = new DynamicObject()
{
	CustomName = "YourName",
	TagInfo = tagInfo
};
gradeObj.AddProperty("Category", "三年级", "年级", "班级描述", "基本属性", true, null, true);
gradeObj.AddProperty("Type", "", "二班", "班级", "基本属性", true, null, true);
PropertyGrid.SelectedObject = gradeObj;

// 读取
DynamicObject customroperty = (DynamicObject)PropertyGrid.SelectedObject;
string catStr = customroperty.GetDynamicProperty("Category").GetValue("Category").ToString();