/// <summary> /// 若使用【读写分离】,查询【从库】条件cmdText.StartsWith("SELECT "),否则查询【主库】 /// </summary> /// <param name="readerHander"></param> /// <param name="cmdType"></param> /// <param name="cmdText"></param> /// <param name="cmdParms"></param> /// <returns></returns> async public Task ExecuteReaderAsync(Func <NpgsqlDataReader, Task> readerHander, CommandType cmdType, string cmdText, params NpgsqlParameter[] cmdParms) { DateTime dt = DateTime.Now; string logtxt = ""; DateTime logtxt_dt = DateTime.Now; var pool = this.MasterPool; bool isSlave = false; //读写分离规则 if (this.SlavePools.Any() && cmdText.StartsWith("SELECT ", StringComparison.CurrentCultureIgnoreCase)) { var availables = slaveUnavailables == 0 ? //查从库 this.SlavePools : ( //查主库 slaveUnavailables == this.SlavePools.Count ? new List <NpgsqlConnectionPool>() : //查从库可用 this.SlavePools.Where(sp => sp.IsAvailable).ToList()); if (availables.Any()) { isSlave = true; pool = availables.Count == 1 ? this.SlavePools[0] : availables[slaveRandom.Next(availables.Count)]; } } Object <NpgsqlConnection> conn = null; NpgsqlCommand cmd = PrepareCommandAsync(cmdType, cmdText, cmdParms, ref logtxt); if (IsTracePerformance) { logtxt += $"PrepareCommand: {DateTime.Now.Subtract(logtxt_dt).TotalMilliseconds}ms Total: {DateTime.Now.Subtract(dt).TotalMilliseconds}ms\r\n"; } Exception ex = null; try { if (IsTracePerformance) { logtxt_dt = DateTime.Now; } if (isSlave) { //从库查询切换,恢复 bool isSlaveFail = false; try { if (cmd.Connection == null) { cmd.Connection = (conn = await pool.GetAsync()).Value; } //if (slaveRandom.Next(100) % 2 == 0) throw new Exception("测试从库抛出异常"); } catch { isSlaveFail = true; } if (isSlaveFail) { if (conn != null) { if (IsTracePerformance) { logtxt_dt = DateTime.Now; } pool.Return(conn, ex); if (IsTracePerformance) { logtxt += $"ReleaseConnection: {DateTime.Now.Subtract(logtxt_dt).TotalMilliseconds}ms Total: {DateTime.Now.Subtract(dt).TotalMilliseconds}ms"; } } LoggerException(pool, cmd, new Exception($"连接失败,准备切换其他可用服务器"), dt, logtxt, false); cmd.Parameters.Clear(); await ExecuteReaderAsync(readerHander, cmdType, cmdText, cmdParms); return; } } else { //主库查询 if (cmd.Connection == null) { cmd.Connection = (conn = await pool.GetAsync()).Value; } } if (IsTracePerformance) { logtxt += $"Open: {DateTime.Now.Subtract(logtxt_dt).TotalMilliseconds}ms Total: {DateTime.Now.Subtract(dt).TotalMilliseconds}ms\r\n"; logtxt_dt = DateTime.Now; } using (NpgsqlDataReader dr = await cmd.ExecuteReaderAsync() as NpgsqlDataReader) { if (IsTracePerformance) { logtxt += $"ExecuteReader: {DateTime.Now.Subtract(logtxt_dt).TotalMilliseconds}ms Total: {DateTime.Now.Subtract(dt).TotalMilliseconds}ms\r\n"; } while (true) { if (IsTracePerformance) { logtxt_dt = DateTime.Now; } bool isread = await dr.ReadAsync(); if (IsTracePerformance) { logtxt += $" dr.Read: {DateTime.Now.Subtract(logtxt_dt).TotalMilliseconds}ms Total: {DateTime.Now.Subtract(dt).TotalMilliseconds}ms\r\n"; } if (isread == false) { break; } if (readerHander != null) { object[] values = null; if (IsTracePerformance) { logtxt_dt = DateTime.Now; values = new object[dr.FieldCount]; for (int a = 0; a < values.Length; a++) { if (!await dr.IsDBNullAsync(a)) { values[a] = await dr.GetFieldValueAsync <object>(a); } } logtxt += $" dr.GetValues: {DateTime.Now.Subtract(logtxt_dt).TotalMilliseconds}ms Total: {DateTime.Now.Subtract(dt).TotalMilliseconds}ms\r\n"; logtxt_dt = DateTime.Now; } await readerHander(dr); if (IsTracePerformance) { logtxt += $" readerHander: {DateTime.Now.Subtract(logtxt_dt).TotalMilliseconds}ms Total: {DateTime.Now.Subtract(dt).TotalMilliseconds}ms ({string.Join(",", values)})\r\n"; } } } if (IsTracePerformance) { logtxt_dt = DateTime.Now; } dr.Close(); } if (IsTracePerformance) { logtxt += $"ExecuteReader_dispose: {DateTime.Now.Subtract(logtxt_dt).TotalMilliseconds}ms Total: {DateTime.Now.Subtract(dt).TotalMilliseconds}ms\r\n"; } } catch (Exception ex2) { ex = ex2; } if (conn != null) { if (IsTracePerformance) { logtxt_dt = DateTime.Now; } pool.Return(conn, ex); if (IsTracePerformance) { logtxt += $"ReleaseConnection: {DateTime.Now.Subtract(logtxt_dt).TotalMilliseconds}ms Total: {DateTime.Now.Subtract(dt).TotalMilliseconds}ms"; } } LoggerException(pool, cmd, ex, dt, logtxt); cmd.Parameters.Clear(); }