using FreeSql; using Microsoft.Extensions.DependencyInjection; using MySql.Data.MySqlClient; using System.Data; using System.Security.Cryptography; namespace StoreHub.KJDWebService.Commons { public class MysqlUtils { public string Message = ""; /// /// 数据库连接字符串 /// private string ConnString = ""; /// /// 数据库连接 /// private MySqlConnection Conn; /// /// 数据库读取对象 /// private MySqlDataReader reader; /// /// 数据库执行对象 /// private MySqlCommand cmd = new MySqlCommand(); /// /// 错误信息 /// //public static string ErrorString = ""; /// /// 超时(秒) /// public int TimeOut = 120; /// /// 链接状态 /// public bool Connected { get { return Conn != null && Conn.State == ConnectionState.Open; } } /// /// 是否正在执行 /// public bool IsRunning = false; public bool IsUseTrans { get; set; } = false; public MySqlTransaction Transaction { get; set; } = null; /// /// 初始化数据库链接 /// /// 数据库链接 public MysqlUtils(string connString, bool isUseTrans = false) { this.IsUseTrans = isUseTrans; ConnString = KJDConfig.GetConnection(connString); ConnTo(); } /// /// 去掉SQL中的特殊字符 /// /// 字符串 /// public string ReplaceSql(string value) { return ReplaceSqlSpecial(value); } /// /// 反转字符串,用于mysql反向索引 /// /// /// public static string ReverseString(string temp) { if (string.IsNullOrEmpty(temp)) return null; char[] l = temp.ToCharArray(); Array.Reverse(l); return new string(l); } /// /// 去掉SQL中的特殊字符 /// /// 字符串 /// public static string ReplaceSqlSpecial(string value) { if (string.IsNullOrEmpty(value)) return null; value = value.Replace("\\", "\\\\"); value = value.Replace("'", "''"); //value = value.Replace("\"", "\\\""); return value; } ///// ///// 开放一个Conn获取路径,以便外部使用事务提交 ///// //public MySqlConnection GetConn() //{ // //Transaction = Conn.BeginTransaction(); // return Conn; //} /// /// 插入数据 /// /// /// /// public int Insert(string table, List keys) { string temp = "", tempx = ""; for (int i = 0; i < keys.Count; i++) { temp += ",`" + keys[i].Key + "`"; tempx += ",'" + keys[i].Value + "'"; } temp = temp.Substring(1); tempx = tempx.Substring(1); string sql = "insert into " + table + " (" + temp + ") values (" + tempx + ") "; return (int)ExecuteInsertId(sql); } /// /// 返回执行表 /// /// /// public DataTable ExecuteDataTable(string SqlString) { return ExecuteDataTable(SqlString, null); } /// /// 执行sql返回DataTable /// /// SQL语句 /// Sql参数 /// DataTable public DataTable ExecuteDataTable(string SqlString, MySqlParameter[] parms) { SleepOrGo(); bool frist = true; Retry: if (Conn == null || Conn.State != ConnectionState.Open) ConnTo(); try { CmdIni(); cmd.CommandText = SqlString; if (parms != null) foreach (MySqlParameter pram in parms) cmd.Parameters.Add(pram); DataSet ds = new DataSet(); MySqlDataAdapter adapter = new MySqlDataAdapter(); adapter.SelectCommand = cmd; adapter.Fill(ds); return ds.Tables[0]; //DataTable dt = new DataTable(); //try //{ // reader = cmd.ExecuteReader(); // dt.Load(reader); //} //catch //{ // reader = cmd.ExecuteReader(); // dt = Read(ref reader); //} //return dt; } catch (Exception e) { if (frist) { frist = false; ErrorDoing(e.Message); goto Retry; } AddError(e.Message, SqlString); return null; } finally { CloseReader(); IsRunning = false; } } /// /// 针对不同错误,执行不同的修正 /// /// private void ErrorDoing(string message) { Message = message; if (string.IsNullOrEmpty(message)) return; if (message.Contains("Incorrect string value")) return; if (message.Contains("Connection must be valid and open")) ConnTo(); if (message.Contains("There is already an open DataReader")) { Thread.Sleep(500); ConnTo(); } if (message.Contains("Fatal error encountered during command execution.")) ConnTo(); if (message.Contains(" StreamWriter ") || message.Contains("未将对象引用设置到对象的实例") || message.Contains("未将对象")) ConnTo(); CloseReader(); Random ra = new Random(Guid.NewGuid().GetHashCode()); Thread.Sleep(ra.Next(200, 2000)); } /// /// 关闭读取线程 /// private void CloseReader() { try { if (reader != null && !reader.IsClosed) reader.Close(); cmd.Dispose(); //reader = null; } catch { } } /// /// 返回执行行 /// /// /// public DataRow ExecuteDataTableRow(string SqlString) { return ExecuteDataTableRow(SqlString, null); } /// /// 返回第一行 /// /// /// public DataRow ExecuteDataTableRow(string SqlString, MySqlParameter[] parms) { SleepOrGo(); bool frist = true; Retry: if (Conn == null || Conn.State != ConnectionState.Open) ConnTo(); try { CmdIni(); cmd.CommandText = SqlString; if (parms != null) foreach (MySqlParameter pram in parms) cmd.Parameters.Add(pram); DataSet ds = new DataSet(); MySqlDataAdapter adapter = new MySqlDataAdapter(); adapter.SelectCommand = cmd; adapter.Fill(ds); DataTable dt = ds.Tables[0]; if (dt.Rows.Count > 0) return dt.Rows[0]; } catch (Exception e) { if (frist) { frist = false; ErrorDoing(e.Message); goto Retry; } AddError(e.Message, SqlString); } finally { CloseReader(); IsRunning = false; } return null; } /// /// 返回第一个执行结果 /// /// /// public int ExecuteRowCount(string SqlString) { string f = ExecuteFirst(SqlString, null); int c; int.TryParse(f, out c); return c; } public int ExecuteRowCount(string SqlString, MySqlParameter[] parms) { string f = ExecuteFirst(SqlString, parms); int c; int.TryParse(f, out c); return c; } /// /// 返回第一个执行结果 /// /// /// public string ExecuteFirst(string SqlString) { return ExecuteFirst(SqlString, null); } /// /// 返回第一个执行结果 /// /// /// public int ExecuteFirstInt(string SqlString, MySqlParameter[] parms = null) { string id = ExecuteFirst(SqlString, parms); int i; int.TryParse(id, out i); return i; } /// /// 返回第一个执行结果 /// /// /// public decimal ExecuteFirstDecimal(string SqlString, MySqlParameter[] parms = null) { string id = ExecuteFirst(SqlString, parms); decimal i; decimal.TryParse(id, out i); return i; } /// /// 返回第一个值 /// /// /// public string ExecuteFirst(string SqlString, MySqlParameter[] parms) { SleepOrGo(); bool frist = true; Retry: if (Conn == null || Conn.State != ConnectionState.Open) ConnTo(); try { CmdIni(); cmd.CommandText = SqlString; if (parms != null) foreach (MySqlParameter pram in parms) cmd.Parameters.Add(pram); reader = cmd.ExecuteReader(); if (reader.Read()) return reader[0].ToString(); return ""; } catch (Exception e) { if (e.Message.Contains("Illegal mix of collations")) return null; if (frist) { frist = false; ErrorDoing(e.Message); goto Retry; } AddError(e.Message, SqlString); } finally { CloseReader(); IsRunning = false; } return null; } /// /// 返回更改、插入或删除的行数 /// /// /// /// public int ExecuteAffectedRows(string SqlString) { return ExecuteAffectedRows(SqlString, null); } /// /// 返回更改、插入或删除的行数 /// /// /// /// public int ExecuteAffectedRows(string SqlString, MySqlParameter[] parms) { SleepOrGo(); bool frist = true; Retry: if (Conn == null || Conn.State != ConnectionState.Open) ConnTo(); try { CmdIni(); cmd.CommandText = SqlString; if (parms != null) foreach (MySqlParameter pram in parms) cmd.Parameters.Add(pram); reader = cmd.ExecuteReader(); if (reader.Read()) return reader.RecordsAffected; return reader.RecordsAffected; } catch (Exception e) { if (e.Message.Contains("Illegal mix of collations")) return 0; if (frist) { frist = false; ErrorDoing(e.Message); goto Retry; } AddError(e.Message, SqlString); } finally { CloseReader(); IsRunning = false; } return 0; } /// /// 返回插入ID /// /// /// public long ExecuteInsertId(string SqlString) { return ExecuteInsertId(SqlString, null); } /// /// 返回第一个值 /// /// /// public long ExecuteInsertId(string SqlString, MySqlParameter[] parms) { SleepOrGo(); bool frist = true; Retry: if (Conn == null || Conn.State != ConnectionState.Open) ConnTo(); try { CmdIni(); cmd.CommandText = SqlString; if (parms != null) foreach (MySqlParameter pram in parms) cmd.Parameters.Add(pram); cmd.ExecuteNonQuery(); long id = cmd.LastInsertedId; return id; } catch (Exception e) { if (e.Message.Contains(" for key 'PRIMARY'") && e.Message.Contains("Duplicate entry")) return 0; if (frist) { frist = false; ErrorDoing(e.Message); goto Retry; } AddError(e.Message, SqlString); } finally { CloseReader(); IsRunning = false; } return 0; } /// /// 无返回 /// /// /// public bool ExecuteNonQuery(string SqlString) { return ExecuteNonQuery(SqlString, null); } /// /// 只保留mysql可识别的字符串 /// /// public string JustUtf8Words(string text) { JustUtf8Words(ref text); return text; } /// /// 只保留mysql可识别的字符串 /// /// public void JustUtf8Words(ref string text) { if (string.IsNullOrEmpty(text)) return; var cs = text.ToCharArray(); List cc = new List(); foreach (char c in cs) { if (c > 7814 && c < 8416 || c > 57096 && c < 59501 || c > 63707 && c < 64309 || c > 65505 || c < 0) { if (cc.Contains(c)) continue; text = text.Replace(c.ToString(), ""); cc.Add(c); } } } /// /// 执行无返回SQL语句 /// /// SQL语句 /// Sql参数 ///是否执行成功 public bool ExecuteNonQuery(string SqlString, MySqlParameter[] parms) { SleepOrGo(); bool frist = true; Retry: if (Conn == null || Conn.State != ConnectionState.Open) ConnTo(); try { CmdIni(); cmd.CommandText = SqlString; if (parms != null) foreach (MySqlParameter pram in parms) cmd.Parameters.Add(pram); cmd.ExecuteNonQuery(); return true; } catch (Exception e) { if (e.Message.Contains("Illegal mix of collations") || e.Message.Contains("Incorrect string value") || e.Message.Contains(" for key 'PRIMARY'") && e.Message.Contains("Duplicate entry")) return false; if (frist) { frist = false; ErrorDoing(e.Message); goto Retry; } AddError(e.Message, SqlString); return false; } finally { CloseReader(); IsRunning = false; } } /// /// 判断是否存在 /// /// /// public bool ExecuteExists(string SqlString) { return ExecuteExists(SqlString, null); } /// /// 查询是否存在 /// /// SQL语句 /// SQL参数 /// 是否存在 public bool ExecuteExists(string SqlString, MySqlParameter[] parms) { SleepOrGo(); bool frist = true; Retry: if (Conn == null || Conn.State != ConnectionState.Open) ConnTo(); try { CmdIni(); cmd.CommandText = SqlString; if (parms != null) foreach (MySqlParameter pram in parms) cmd.Parameters.Add(pram); reader = cmd.ExecuteReader(); if (reader.Read()) return true; return false; } catch (Exception e) { if (frist) { frist = false; ErrorDoing(e.Message); goto Retry; } AddError(e.Message, SqlString); return false; } finally { CloseReader(); IsRunning = false; } } /// /// 停止还是前进 /// private void SleepOrGo() { int i = 0; while (IsRunning && i < 300) { Thread.Sleep(100); i++; } IsRunning = true; } /// /// 初始化CMD /// private void CmdIni() { if (reader != null && !reader.IsClosed) reader.Close(); if (cmd != null) cmd.Dispose(); cmd = new MySqlCommand(); cmd.Connection = Conn; cmd.CommandType = CommandType.Text; cmd.CommandTimeout = TimeOut; if (Transaction != null) cmd.Transaction = Transaction; } /// /// 连接数据库 /// private void ConnTo() { Close(); try { Conn = new MySqlConnection(ConnString); Conn.Open(); if (IsUseTrans) this.Transaction = Conn.BeginTransaction(); } catch (Exception e) { AddError(e.Message, ConnString); } } /// /// 错误信息 /// /// /// private void AddError(string message, string sql) { if (string.IsNullOrEmpty(message) || message.Contains("Illegal mix of collations")) return; ErrorDoing(message); string errStr = "数据库连接错误:" + message + "\r\nSQL语句:" + sql; try { if (!Directory.Exists("Log")) { Directory.CreateDirectory("Log"); } File.AppendAllText("Log\\log-" + DateTime.Now.ToString("yyyyMMdd") + ".txt", errStr); } catch (Exception ex) { } } public void Commit() { if (Transaction != null) Transaction.Commit(); } public void RollBack() { if (Transaction != null) Transaction.Rollback(); } /// /// 关闭数据库链接 /// public void Close() { IsRunning = false; try { if (Conn != null && Conn.State == ConnectionState.Open) { Conn.Close(); } Conn = null; try { if (reader != null && !reader.IsClosed) reader.Close(); } catch { } reader = null; try { if (Transaction != null) Transaction.Dispose(); } catch { } Transaction = null; } catch { } } } public class MysqlKeyValues { public List List = new List(); } public class MysqlKeyValue { public MysqlKeyValue(string key, object value) { Key = key; Value = value == null ? "" : MysqlUtils.ReplaceSqlSpecial(value.ToString()); } public string Key = ""; public string Value; } /// /// 根据连接串 key 提供 FreeSql IAdo(由框架 DI 注册的 keyed IFreeSql 提供) /// public static class AdoProvider { private static IServiceProvider _serviceProvider; public static void SetServiceProvider(IServiceProvider serviceProvider) { _serviceProvider = serviceProvider; } public static IAdo Get(string connKey) { if (string.IsNullOrEmpty(connKey)) connKey = "ConnKJD"; string key = connKey switch { "ConnKJD" => "KJDDB", "ConnKJDBAK" => "KJDBAKDB", _ => "KJDDB", }; var fsql = _serviceProvider?.GetKeyedService(key); if (fsql == null) { var fsql2 = _serviceProvider?.GetService(); if (fsql2 != null) return fsql2.Ado; throw new InvalidOperationException("IFreeSql not registered for key " + key); } return fsql.Ado; } } }