При создании UnitOfWork необязательно начинать транзакцию БД сразу и в лоб. Так как даже работа с доменными объектами может не потребовать БД до самого момента комита UnitOfWork - и соединение к БД не будет держаться без дела паразитно. Всё зависит от реализации UnitOfWork и той инфраструктуры на которой он живёт.
На C# я могу хоть триллион IF сделать. Шаг №1 - Генерирую DLL на N штук IF - загружаю в память и использую ... Шfг №M - Генерирую DLL на N штук IF - загружаю в память и использую
Если о кэше - есть ключевые точки - обновление, удаление, выборка. Они причины движений в кэше. Это помимо протухания элемента кэша по TTL и есть еще принудительное автоматическое удаление элемента из кэша при подозрении на рассинхрон с БД.
Моя библиотека только в комплексе даёт профит. Просто голый кэш мапера это недостаточно для вкусной жизни ПО.
В генерированом коде реализовано понятие сокрытии записи, оптимистическая конкуренция при обновлении записи.
Помимо CRUD создаётся код с типичными запросами:
Выборка по альтернативному ключу (ключам).
Выборка по полю (полям) группировки.
Создание WHERE специфичного для БД (SQL Server и PostgreSQL) по запросу собраному в C# или из текста.
Постраничная выборка (с и без WHERE).
Все генерируемые мапперы поддерживают кэширования при выборке объектов по первичному ключу. По мониторингу боевых серверов - попадания к кэш стремится с 99%, что сильно разгружает сеть и БД. Рассинхрон кэша и БД решается автоматически.
Реализовано создания изначений первичных ключей на основе последовательностей БД с минимальной нагрузкой на саму БД.
/// <summary>
/// Получить запись с указаным идентити.
/// </summary>
/// <param name="mappersSession">Сессия БД.</param>
/// <param name="id">Идентити записи.</param>
/// <param name="cancellationToken">Токен отмены.</param>
/// <returns>Возвращает значение если запись существует иначе возвращает <see langword="null" /> если запись не существует.</returns>
[SuppressMessage("ReSharper", "UseObjectOrCollectionInitializer")]
[SuppressMessage("ReSharper", "ConvertIfStatementToConditionalTernaryExpression")]
[SuppressMessage("ReSharper", "RedundantCast")]
public virtual async ValueTask<IMapperDto> GetAsync(IMappersSession mappersSession, long id, CancellationToken cancellationToken = default)
{
if (mappersSession == null)
{
throw new ArgumentNullException(nameof(mappersSession));
}
try
{
var typedSession = (IPostgreSqlMappersSession)mappersSession;
// ReSharper disable once ConvertToUsingDeclaration
var command = await typedSession.CreateCommandAsync(false, cancellationToken).ConfigureAwait(false);
await using (command.ConfigureAwait(false))
{
command.CommandType = CommandType.Text;
command.CommandText = @"SELECT
Id FROM ChangeTracker WHERE (Id = @Id)";
{
var parameter = new NpgsqlParameter<long>("@Id", NpgsqlDbType.Bigint) { TypedValue = id };
command.Parameters.Add(parameter);
}
var reader = await command.ExecuteReaderAsync(CommandBehavior.SequentialAccess | CommandBehavior.SingleResult, cancellationToken).ConfigureAwait(false);
await using (reader.ConfigureAwait(false))
{
if (await reader.ReadAsync(cancellationToken).ConfigureAwait(false))
{
GetColumnIndexes(
reader,
out var indexId);
var result = Read(
reader,
indexId);
return ((IMapperDto)result);
}
}
return ((IMapperDto)null);
}
}
catch (Exception exception)
{
CatchExceptionOnGet(mappersSession, exception, id);
CatchException(mappersSession, exception);
var targetException = await m_exceptionPolicy.ApplyAsync(exception, cancellationToken).ConfigureAwait(false);
if (ReferenceEquals(targetException, exception))
{
ExceptionDispatchInfo.Capture(exception).Throw();
}
throw targetException;
}
Осталось физически реализовать машину Тьюринга
и запустить на ней Doom ❤️
Осталось сделать ИИ который будет смотреть видео созданные ИИ.
И YouTube достигнет сингулярности развития.
❤️
Если застрелить всех лошадей.
Так можно гарантированно избавится от проблемы поиска самой быстрой.
Хотя вдруг быстрота была на быстроту степени полного разложения ? Хм … трудно 🐸
Какой бред.
Играют для фанатов и получить приятное приключение.
И выполнять миссии и прочее получая перки - доя этого никаких манипуляций не надо .
Игрок сам для этого пришел в игру.
манипуляции были до момента оплаты игроком денег - далее только приключение по желанию игрока .
Какие все глупые .
Надо не 2 сети делать а 3 которая будет контролить первых 2 х если они вдруг налажают
Мы пошли дальше.
Сделали шаблон сервера с полным фаршем что нужен серверам.
Логирование, телеметрия, DDD, тесты и прочее…
https://github.com/KlestovAlexej/Wattle3.DemoServer
Поделюсь опытом реализации хранилища ключей для идемпотентных операций.
Тут полный пример как хранить в БД и в памяти 1.000.000.000 (миллиард) ключей и запускать сервер за 17 секунд с полной загрузкой ключей в память.
Всё сделано на C# как готовый компонент.
https://github.com/KlestovAlexej/Wattle3.Examples?tab=readme-ov-file#пример-старта-реестра-на-1000000000-уникальных-ключей-1712-секунд
Реестр уникальных ключей реализует :
Хранение ключей в оперативной памяти и в БД.
Ключи могут быть ассоциированы с произвольными данными, тоже хранимыми в памяти.
Поиск ключа или данных по ключу происходит только в оперативной памяти и не задействует БД.
Параллельная регистрация одного и того же уникального ключа не приводит к задвоениям или рассинхронизациям с БД.
Есть сборка мусора - устаревшие ключи и данные автоматически удаляются из оперативной памяти по критерию заданным программистом.
Адаптирован для применения партиционирования PostgreSQL таблицы ключей для изятия устаревших ключей из памяти и БД.
Хранение ключей и данных в оперативной памяти оптимизировано и не нагружает сборщик мусора.
Ключи и данные в оперативной памяти занимают места O(Число ключей * (размер ключа + размер данных)) и не расходуют память на служебную информацию CLR.
Регистрация нового ключа задействует БД только в момент подтверждения Unit of Work.
Регистрация нового ключа отменяется автоматически в аварийных ситуациях работы Unit of Work.
У меня на C# создания QR и запроса статуса оплаы.
https://github.com/KlestovAlexej/SbpPoint.Examples/blob/f09e5a64ee6b2a85b1fb5199de704f8085c1a7b3/Gateway/Examples.cs#L315
Вставлю свои 5 копеек, но в терминах C# на примере моей демки https://github.com/KlestovAlexej/Wattle3.DemoServer
При создании UnitOfWork необязательно начинать транзакцию БД сразу и в лоб.
Так как даже работа с доменными объектами может не потребовать БД до самого момента комита UnitOfWork - и соединение к БД не будет держаться без дела паразитно.
Всё зависит от реализации UnitOfWork и той инфраструктуры на которой он живёт.
На C# я могу хоть триллион IF сделать.
Шаг №1 - Генерирую DLL на N штук IF - загружаю в память и использую
...
Шfг №M - Генерирую DLL на N штук IF - загружаю в память и использую
В итоге N * F операторов IF.
Вуаля !
Если о кэше - есть ключевые точки - обновление, удаление, выборка.
Они причины движений в кэше.
Это помимо протухания элемента кэша по TTL и есть еще принудительное автоматическое удаление элемента из кэша при подозрении на рассинхрон с БД.
Моя библиотека только в комплексе даёт профит.
Просто голый кэш мапера это недостаточно для вкусной жизни ПО.
Помимо мапера в доменной области есть стратегия решения конфликтной ситуации при комите в БД - система автоматически даёт программисту уведомление что комит успешен (данные в БД) или не успешен (данные не в БД) - даже если данные в БД попали, а их потом физически удалил.
Причём где бы не упал код до комита или даже в момент самого комита transaction.Commit().
В демо сервер есть примеры https://github.com/KlestovAlexej/Wattle3.DemoServer/blob/c9074eb2604efae8c8f8926ec843806193547651/src/DemoServer.Processing.Model/DomainObjects/DemoObjectX/DomainObjectDemoObjectX.cs#L226.
Система автоматически понимает - следит на транзакциями БД отслеживает их делает сверки с БД (у каждой БД свои маперы которые знают специфику).
Всё из коробки.
Да моя библиотека (C# https://github.com/KlestovAlexej/Wattle3.Examples) генерирует CRUD но и много сопутствующих фичей полезных на практике.
В генерированом коде реализовано понятие сокрытии записи, оптимистическая конкуренция при обновлении записи.
Помимо CRUD создаётся код с типичными запросами:
Выборка по альтернативному ключу (ключам).
Выборка по полю (полям) группировки.
Создание WHERE специфичного для БД (SQL Server и PostgreSQL) по запросу собраному в C# или из текста.
Постраничная выборка (с и без WHERE).
Все генерируемые мапперы поддерживают кэширования при выборке объектов по первичному ключу.
По мониторингу боевых серверов - попадания к кэш стремится с 99%, что сильно разгружает сеть и БД.
Рассинхрон кэша и БД решается автоматически.
Реализовано создания изначений первичных ключей на основе последовательностей БД с минимальной нагрузкой на саму БД.
Что-то подобное для продакшен использовании я на C# сделал.
Идёт генерация мапперов с полным CRUD на ADO.NET.
Поддерживается SQL Server и PostgreSQL.
Демонстрационный сервер тут https://github.com/KlestovAlexej/Wattle3.DemoServer
К примеру метод маппера GetAsync :
https://github.com/KlestovAlexej/Wattle3.DemoServer/blob/31bd12fe5e68af449b3e88f8e9c6e3b2597815b2/src/DemoServer.Processing.DataAccess.Postgresql/Generated/ShtrihM.Wattle3.CodeGeneration.Generator.Implements/ShtrihM.Wattle3.CodeGeneration.Generator.Implements.SourceGenerator/DbMappers.Implements.PostgreSql.Generated.cs#L1304
Id
FROM ChangeTracker WHERE
(Id = @Id)";