2023-12-29 16:16:05 +08:00
|
|
|
|
using System.Text;
|
|
|
|
|
using ConsoleApp2.Helpers;
|
|
|
|
|
using Microsoft.Extensions.Logging;
|
|
|
|
|
using MySqlConnector;
|
2024-01-12 16:50:37 +08:00
|
|
|
|
using ServiceStack;
|
2023-12-29 16:16:05 +08:00
|
|
|
|
|
|
|
|
|
namespace ConsoleApp2.Services;
|
|
|
|
|
|
2024-01-04 09:00:44 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// Mysql导出
|
|
|
|
|
/// </summary>
|
2023-12-29 16:16:05 +08:00
|
|
|
|
public class MySqlDestination : IDisposable, IAsyncDisposable
|
|
|
|
|
{
|
|
|
|
|
private readonly Dictionary<string, IList<DataRecord>> _recordCache;
|
|
|
|
|
private readonly MySqlConnection _conn;
|
|
|
|
|
private readonly ILogger _logger;
|
|
|
|
|
private readonly bool _prettyOutput;
|
2024-01-12 16:50:37 +08:00
|
|
|
|
private readonly int _maxAllowPacket;
|
|
|
|
|
private readonly ProcessContext _context;
|
|
|
|
|
private static StringBuilder recordSb = new StringBuilder();
|
|
|
|
|
public MySqlDestination(string connStr, ILogger logger, ProcessContext context,bool prettyOutput = false)
|
2023-12-29 16:16:05 +08:00
|
|
|
|
{
|
|
|
|
|
_conn = new MySqlConnection(connStr);
|
|
|
|
|
_conn.Open();
|
|
|
|
|
_recordCache = new Dictionary<string, IList<DataRecord>>();
|
|
|
|
|
_logger = logger;
|
2024-01-12 16:50:37 +08:00
|
|
|
|
_context = context;
|
2023-12-29 16:16:05 +08:00
|
|
|
|
_prettyOutput = prettyOutput;
|
|
|
|
|
|
2024-01-12 16:50:37 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
}
|
2023-12-29 16:16:05 +08:00
|
|
|
|
public Task WriteRecordAsync(DataRecord record)
|
|
|
|
|
{
|
|
|
|
|
_recordCache.AddOrUpdate(record.TableName, [record], (key, value) =>
|
|
|
|
|
{
|
|
|
|
|
value.Add(record);
|
|
|
|
|
return value;
|
|
|
|
|
});
|
|
|
|
|
return Task.CompletedTask;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public async Task WriteRecordsAsync(IEnumerable<DataRecord> records)
|
|
|
|
|
{
|
|
|
|
|
foreach (var record in records)
|
|
|
|
|
{
|
|
|
|
|
await WriteRecordAsync(record);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-01-12 16:50:37 +08:00
|
|
|
|
public async Task FlushAsync(int maxAllowPacket)
|
2023-12-29 16:16:05 +08:00
|
|
|
|
{
|
|
|
|
|
if (_recordCache.Count == 0)
|
|
|
|
|
return;
|
2024-01-12 16:50:37 +08:00
|
|
|
|
|
|
|
|
|
//var cmd = _conn.CreateCommand();
|
|
|
|
|
//cmd.CommandTimeout = 3 * 60;
|
|
|
|
|
|
2023-12-29 16:16:05 +08:00
|
|
|
|
try
|
|
|
|
|
{
|
2024-01-12 16:50:37 +08:00
|
|
|
|
var excuseList = GetExcuseList(_recordCache, maxAllowPacket, _prettyOutput);
|
|
|
|
|
//foreach (var insertSql in excuseList)
|
|
|
|
|
//{
|
|
|
|
|
// //cmd.CommandText = insertSql;
|
|
|
|
|
// //await cmd.ExecuteNonQueryAsync();
|
|
|
|
|
// //_logger.LogInformation(@"do insert completed!size:{Length}", cmd.CommandText.Length);
|
|
|
|
|
//}
|
2023-12-29 16:16:05 +08:00
|
|
|
|
_recordCache.Clear();
|
|
|
|
|
}
|
|
|
|
|
catch (Exception e)
|
|
|
|
|
{
|
2024-01-12 16:50:37 +08:00
|
|
|
|
//_logger.LogCritical(e, "Error when flushing records, sql: {Sql}", cmd.CommandText.Omit(1000));
|
|
|
|
|
_context.AddException(e);
|
2023-12-29 16:16:05 +08:00
|
|
|
|
throw;
|
|
|
|
|
}
|
2024-01-04 09:00:44 +08:00
|
|
|
|
finally
|
|
|
|
|
{
|
2024-01-12 16:50:37 +08:00
|
|
|
|
//await cmd.DisposeAsync();
|
2024-01-04 09:00:44 +08:00
|
|
|
|
}
|
2023-12-29 16:16:05 +08:00
|
|
|
|
}
|
|
|
|
|
|
2024-01-12 16:50:37 +08:00
|
|
|
|
public static IList<string> GetExcuseList(IDictionary<string, IList<DataRecord>> tableRecords,int maxAllowPacket,
|
|
|
|
|
bool prettyOutput = false)
|
2023-12-29 16:16:05 +08:00
|
|
|
|
{
|
2024-01-12 16:50:37 +08:00
|
|
|
|
var resultList = new List<string>();
|
|
|
|
|
var headerSb = string.Empty;
|
|
|
|
|
//var recordSb = new StringBuilder();
|
|
|
|
|
recordSb.Clear();
|
2023-12-29 16:16:05 +08:00
|
|
|
|
foreach (var (tableName, records) in tableRecords)
|
|
|
|
|
{
|
|
|
|
|
if (records.Count == 0)
|
|
|
|
|
continue;
|
2024-01-12 16:50:37 +08:00
|
|
|
|
headerSb=$"INSERT INTO `{tableName}`(";
|
2023-12-29 16:16:05 +08:00
|
|
|
|
for (var i = 0; i < records[0].Headers.Length; i++)
|
|
|
|
|
{
|
|
|
|
|
var header = records[0].Headers[i];
|
2024-01-12 16:50:37 +08:00
|
|
|
|
headerSb+=$"`{header}`";
|
2023-12-29 16:16:05 +08:00
|
|
|
|
if (i != records[0].Headers.Length - 1)
|
2024-01-12 16:50:37 +08:00
|
|
|
|
headerSb.Append(',');
|
2023-12-29 16:16:05 +08:00
|
|
|
|
}
|
|
|
|
|
|
2024-01-12 16:50:37 +08:00
|
|
|
|
headerSb+=") VALUES ";
|
2023-12-29 16:16:05 +08:00
|
|
|
|
if (prettyOutput)
|
2024-01-12 16:50:37 +08:00
|
|
|
|
headerSb+="/r/n";
|
2023-12-29 16:16:05 +08:00
|
|
|
|
|
2024-01-12 16:50:37 +08:00
|
|
|
|
var sbList = new List<string>();
|
|
|
|
|
var currentLength = headerSb.Length;
|
2023-12-29 16:16:05 +08:00
|
|
|
|
for (var i = 0; i < records.Count; i++)
|
|
|
|
|
{
|
|
|
|
|
var record = records[i];
|
2024-01-12 16:50:37 +08:00
|
|
|
|
recordSb.Append('(');
|
2023-12-29 16:16:05 +08:00
|
|
|
|
for (var j = 0; j < record.Fields.Length; j++)
|
|
|
|
|
{
|
|
|
|
|
var field = record.Fields[j];
|
2024-01-12 16:50:37 +08:00
|
|
|
|
recordSb.Append(field);
|
2023-12-29 16:16:05 +08:00
|
|
|
|
if (j != record.Fields.Length - 1)
|
2024-01-12 16:50:37 +08:00
|
|
|
|
recordSb.Append(',');
|
2023-12-29 16:16:05 +08:00
|
|
|
|
}
|
|
|
|
|
|
2024-01-12 16:50:37 +08:00
|
|
|
|
recordSb.Append(')');
|
2023-12-29 16:16:05 +08:00
|
|
|
|
|
2024-01-12 16:50:37 +08:00
|
|
|
|
//if (i != records.Count - 1) // not last field
|
|
|
|
|
// recordSb.Append(',');
|
|
|
|
|
if (prettyOutput) recordSb.AppendLine();
|
2023-12-29 16:16:05 +08:00
|
|
|
|
|
2024-01-12 16:50:37 +08:00
|
|
|
|
if (currentLength + recordSb.Length >= maxAllowPacket)
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
var insertSb = headerSb;
|
|
|
|
|
|
|
|
|
|
insertSb+=string.Join(",", sbList);
|
|
|
|
|
insertSb += ";";
|
|
|
|
|
resultList.Add(insertSb);
|
|
|
|
|
insertSb=String.Empty;
|
|
|
|
|
sbList.Clear();
|
|
|
|
|
currentLength = headerSb.Length;
|
|
|
|
|
sbList.Add(recordSb.ToString());
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
sbList.Add(recordSb.ToString());
|
|
|
|
|
}
|
|
|
|
|
currentLength += recordSb.Length;
|
|
|
|
|
recordSb.Clear();
|
|
|
|
|
}
|
|
|
|
|
if (sbList.Count > 0)
|
|
|
|
|
{
|
|
|
|
|
var insertSb = headerSb.ToString();
|
|
|
|
|
insertSb += string.Join(",", sbList);
|
|
|
|
|
insertSb += ";";
|
|
|
|
|
resultList.Add(insertSb.ToString());
|
|
|
|
|
insertSb=string.Empty;
|
|
|
|
|
}
|
|
|
|
|
headerSb=string.Empty;
|
2023-12-29 16:16:05 +08:00
|
|
|
|
}
|
|
|
|
|
|
2024-01-12 16:50:37 +08:00
|
|
|
|
return resultList;
|
2023-12-29 16:16:05 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public void Dispose()
|
|
|
|
|
{
|
2024-01-04 09:00:44 +08:00
|
|
|
|
_conn.Close();
|
2023-12-29 16:16:05 +08:00
|
|
|
|
_conn.Dispose();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public async ValueTask DisposeAsync()
|
|
|
|
|
{
|
2024-01-04 09:00:44 +08:00
|
|
|
|
await _conn.CloseAsync();
|
2023-12-29 16:16:05 +08:00
|
|
|
|
await _conn.DisposeAsync();
|
|
|
|
|
}
|
|
|
|
|
}
|