EasyCore.DistributedTransaction.DTM 8.3.0

dotnet add package EasyCore.DistributedTransaction.DTM --version 8.3.0
                    
NuGet\Install-Package EasyCore.DistributedTransaction.DTM -Version 8.3.0
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="EasyCore.DistributedTransaction.DTM" Version="8.3.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="EasyCore.DistributedTransaction.DTM" Version="8.3.0" />
                    
Directory.Packages.props
<PackageReference Include="EasyCore.DistributedTransaction.DTM" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add EasyCore.DistributedTransaction.DTM --version 8.3.0
                    
#r "nuget: EasyCore.DistributedTransaction.DTM, 8.3.0"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package EasyCore.DistributedTransaction.DTM@8.3.0
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=EasyCore.DistributedTransaction.DTM&version=8.3.0
                    
Install as a Cake Addin
#tool nuget:?package=EasyCore.DistributedTransaction.DTM&version=8.3.0
                    
Install as a Cake Tool

🔀 EasyCore.DistributedTransaction.DTM

EasyCore.DistributedTransaction.DTM 是面向 .NET 8 的生产级分布式事务客户端封装。基于开源 DTM 与 Dtmcli,提供 Msg / TCC / Saga / XA 四种模式、子事务屏障、以及 MySQL / PostgreSQL / SQL Server 独立 SQL 支持包。

.NET C# DTM Patterns DB License Version


🌍 Language


📚 目录

第一部分:总览与架构

第二部分:快速上手

第三部分:四种模式详解

第四部分:持久化与生产


1. 项目定位

EasyCore.DistributedTransaction.DTM 解决「在 ASP.NET Core 微服务中快速、正确使用 DTM」的问题:

痛点 EasyCore.DTM 做法
手写 Dtmcli 样板代码多 IEasyCoreDtmMsg / Tcc / Saga / Xa 门面
多库 barrier 方言不一致 MySQL / PostgreSQL / SQL Server 独立包 + 官方 DDL
QueryPrepared 易用错 按 barrier 真实结果映射 DtmResult
核心包绑死 DB 驱动 IDtmDbConnectionFactory,驱动只在提供程序包
缺少 XA IEasyCoreDtmXa(MySQL / PostgreSQL)
返回值耦合 MVC 统一 DtmResult,Controller 自行 Ok(...)

1.1 设计原则

原则 说明
低摩擦接入 一个扩展方法 + 一个 SQL 包即可跑通
模式齐全 Msg / TCC / Saga / XA
存储可插拔 核心与数据库包分离,按需引用
语义对齐上游 Barrier / QueryPrepared / WaitResult 遵循 DTM
失败可感知 DtmResult + 异常不吞

1.2 解决方案目录

EasyCore.DistributedTransaction.DTM/
├── src/
│   ├── EasyCore.DistributedTransaction.DTM/              # 核心:Msg/TCC/Saga/XA
│   ├── EasyCore.DistributedTransaction.DTM.MySql/
│   ├── EasyCore.DistributedTransaction.DTM.PostgreSQL/
│   └── EasyCore.DistributedTransaction.DTM.SqlServer/
├── demo/
│   └── Web.EasyCore.DistributedTransaction.SqlServer/    # Swagger Demo
├── tests/
│   └── EasyCore.DistributedTransaction.DTM.Tests/
└── docs/svg/                                             # README 架构图

2. 架构与模块关系

2.1 组件关系图

architecture-cn

2.2 四种模式一览

patterns-cn

2.3 四种模式时序

📨 Msg

sequence-msg-cn

🧩 TCC

sequence-tcc-cn

🔗 Saga

sequence-saga-cn

⚙️ XA

sequence-xa-cn

2.4 数据流(文字版)

[ASP.NET Controller]
       │
       ▼
 IEasyCoreDtmMsg / Tcc / Saga / Xa
       │
       ▼
   Dtmcli (HTTP) ──────────────► DTM Server
       │                              │
       ▼                              ▼
 IDtmDbConnectionFactory        分支重试 / 回查
       │
       ▼
 barrier 表(MySQL / PG / SQL Server)

3. NuGet / 项目清单

包名 职责 是否必须
EasyCore.DistributedTransaction.DTM 核心门面、DtmResult、DI ✅
EasyCore.DistributedTransaction.DTM.MySql MySQL barrier + XA 三选一
EasyCore.DistributedTransaction.DTM.PostgreSQL PostgreSQL barrier + XA 三选一
EasyCore.DistributedTransaction.DTM.SqlServer SQL Server barrier(无 XA) 三选一

⚠️ Oracle 不在 DtmCommon 1.4 官方方言内,本库不提供 Oracle 包。


4. 事务模式对比

模式 接口 适用场景 备注
📨 Msg IEasyCoreDtmMsg 可靠消息、最终一致 两阶段消息 + QueryPrepared
🧩 TCC IEasyCoreDtmTcc 库存预留、强控资源 Try 失败 → Cancel
🔗 Saga IEasyCoreDtmSaga 长流程、可补偿 Action + Compensate
⚙️ XA IEasyCoreDtmXa 需要 DB XA 仅 MySQL / PostgreSQL

5. 数据库选型对比

能力 MySQL PostgreSQL SQL Server
包 .MySql .PostgreSQL .SqlServer
Barrier ✅ ✅(uniq_barrier) ✅(IGNORE_DUP_KEY)
AutoCreateBarrierTable ✅ ✅ ✅
XA ✅ ✅ ❌
典型场景 Linux 常见栈 云原生 / 开源栈 Windows / 企业库

5.1 选型决策树

需要 XA?
├── 是 → MySQL 或 PostgreSQL
└── 否 → 选已有数据库
        ├── MySQL / MariaDB → EasyCore.DistributedTransaction.DTM.MySql
        ├── PostgreSQL → EasyCore.DistributedTransaction.DTM.PostgreSQL
        └── SQL Server → EasyCore.DistributedTransaction.DTM.SqlServer

6. 环境要求

项 要求
.NET 8.0+
宿主 ASP.NET Core(Web / API)
DTM Server 需单独部署(默认 http://localhost:36789)
Dtmcli 1.4.0(由核心包引入)
数据库 MySQL / PostgreSQL / SQL Server 其一

启动 DTM Server 示例:

git clone https://github.com/dtm-labs/dtm && cd dtm
go run main.go

7. 安装

dotnet add package EasyCore.DistributedTransaction.DTM

# 按需选择其一
dotnet add package EasyCore.DistributedTransaction.DTM.MySql
dotnet add package EasyCore.DistributedTransaction.DTM.PostgreSQL
dotnet add package EasyCore.DistributedTransaction.DTM.SqlServer

8. 三分钟快速开始

8️⃣.1️⃣ 注册服务(MySQL 示例)

using EasyCore.DistributedTransaction.DTM;
using EasyCore.DistributedTransaction.DTM.MySql;

builder.Services.AddEasyCoreDistributedTransactionDtm(options =>
{
    options.DtmUrl = "http://localhost:36789";
    options.AutoCreateBarrierTable = true; // 生产可关

    options.EasyCoreDtmMySql(db =>
    {
        db.ConnectionString =
            "server=localhost;port=3306;user id=root;password=***;database=EasyCoreDtm";
        db.DtmDataBase = "EasyCoreDtm";
    });
});

8️⃣.2️⃣ 发起 Msg 事务

[ApiController]
[Route("api/[controller]")]
public class MsgController : ControllerBase
{
    private readonly IEasyCoreDtmMsg _msg;
    public MsgController(IEasyCoreDtmMsg msg) => _msg = msg;

    [HttpPost("SubmitMsg")]
    public async Task<IActionResult> Submit(CancellationToken ct)
    {
        var branch = new EasyCoreDtmMsgData
        {
            Action = "http://localhost:5039/api/Msg/Branch",
            Data = new { Id = 1, Title = "test" }
        };

        var result = await _msg.DoAndSubmitAsync(
            queryPreparedUrl: "http://localhost:5039/api/Msg/MsgQueryPrepared",
            localAction: async tx =>
            {
                // 与 barrier 同一 DbTransaction 内执行本地业务
                await Task.CompletedTask;
            },
            ct,
            branch);

        return Ok(result.ToResponseBody()); // { "dtm_result": "SUCCESS" }
    }

    [HttpGet("MsgQueryPrepared")]
    public async Task<IActionResult> QueryPrepared(CancellationToken ct)
    {
        var result = await _msg.QueryPreparedAsync(Request.Query, ct);
        return Ok(result.ToResponseBody());
    }

    [HttpPost("Branch")]
    public async Task<IActionResult> Branch()
    {
        var result = await _msg.CallBranchAsync(Request.Query, async tx =>
        {
            // 分支业务
            await Task.CompletedTask;
        });
        return Ok(result.ToResponseBody());
    }
}

9. Msg(两阶段消息)

9.1 模式简介

Msg 将「本地事务」与「消息投递」绑定:Prepare → 本地提交 → Submit → 下游消费;失败由 DTM 重试,并通过 QueryPrepared 回查。

9.2 关键 API

方法 说明
DoAndSubmitAsync 本地屏障事务 + Submit(可带 Func<DbTransaction, Task>)
SubmitWaitResultAsync 启用 WaitResult,等待最终结果
QueryPreparedAsync 回查接口,按 barrier 结果 返回 SUCCESS/FAILURE
CallBranchAsync 下游分支 + 子事务屏障
// 同步等待最终结果
var result = await _msg.SubmitWaitResultAsync(
    "http://localhost:5039/api/Msg/MsgQueryPrepared",
    localAction: null,
    cancellationToken,
    branch);

10. TCC

10.1 模式简介

阶段 含义
Try 资源预留(检查并锁定,不最终提交)
Confirm 确认提交
Cancel 取消 / 释放预留

Try 失败 → DTM 调用 Cancel;Confirm/Cancel 失败会重试直至成功。

10.2 示例

private readonly IEasyCoreDtmTcc _tcc;

[HttpPost("SubmitTcc")]
public async Task<IActionResult> Submit(CancellationToken ct)
{
    var data = new EasyCoreDtmTccData
    {
        TryUrl = "http://localhost:5039/api/Tcc/Try",
        ConfirmUrl = "http://localhost:5039/api/Tcc/Confirm",
        CancelUrl = "http://localhost:5039/api/Tcc/Cancel",
        Data = new { Id = 1 }
    };

    var result = await _tcc.CallBranchAsync(ct, data);
    return Ok(result.ToResponseBody());
}

[HttpPost("Try")]
public async Task<IActionResult> Try() =>
    Ok((await _tcc.TransSucceedResponseAsync()).ToResponseBody());

[HttpPost("Confirm")]
public async Task<IActionResult> Confirm() =>
    Ok((await _tcc.TransSucceedResponseAsync()).ToResponseBody());

[HttpPost("Cancel")]
public async Task<IActionResult> Cancel() =>
    Ok((await _tcc.TransSucceedResponseAsync()).ToResponseBody());

业务失败时返回:

return Ok((await _tcc.TransFailureResponseAsync()).ToResponseBody());

11. Saga

11.1 模式简介

将长事务拆为多个局部事务:正向 Action,失败时按序执行 Compensate。

方法 说明
SubmitAsync 提交后立即返回
SubmitWaitResultAsync 等待最终结果
SubmitConcurrentAsync 并发执行分支

11.2 示例

private readonly IEasyCoreDtmSaga _saga;

[HttpPost("SubmitSaga")]
public async Task<IActionResult> Submit(CancellationToken ct)
{
    var data = new EasyCoreDtmSagaData
    {
        Action = "http://localhost:5039/api/Saga/Action",
        Compensate = "http://localhost:5039/api/Saga/Compensate",
        Data = new { Id = 1 }
    };

    var result = await _saga.SubmitAsync(ct, data);
    return Ok(result.ToResponseBody());
}

[HttpPost("Action")]
public async Task<IActionResult> Action()
{
    // 成功
    return Ok((await _saga.TransSucceedResponseAsync()).ToResponseBody());
    // 失败触发补偿:
    // return Ok((await _saga.TransFailureResponseAsync()).ToResponseBody());
}

[HttpPost("Compensate")]
public async Task<IActionResult> Compensate() =>
    Ok((await _saga.TransSucceedResponseAsync()).ToResponseBody());

⚠️ Saga 分支必须显式返回 SUCCESS / FAILURE(TransSucceedResponseAsync / TransFailureResponseAsync),否则 DTM 无法判定分支结果。


12. XA

12.1 模式简介

XA 由 DTM 协调全局事务:MySQL 执行 xa start / end / prepare / commit | rollback;PostgreSQL 执行 BEGIN → 业务 → PREPARE TRANSACTION → COMMIT/ROLLBACK PREPARED。

数据库 XA 说明
MySQL ✅ InnoDB XA;MySQL < 8.0 注意连接池限制(上游 DTM 文档)
PostgreSQL ✅ 必须开启两阶段提交(见下方「数据库设置」)
SQL Server ❌ 不支持。调用 IEasyCoreDtmXa 会抛 NotSupportedException。请使用 Msg / TCC / Saga

⚠️ Demo 项目名虽含 SqlServer,但 XA 仅在注册 MySQL / PostgreSQL 提供程序时可用。注册 EasyCoreDtmSqlServer 后请勿调用 /api/Xa/*。

12.2 PostgreSQL XA 数据库设置(必做)

PostgreSQL 默认关闭 prepared transactions(max_prepared_transactions = 0)。未开启时 XA 本地分支在 PREPARE TRANSACTION 阶段会报错:

55000: prepared transactions are disabled

1. 设置并重启(该参数修改后必须重启实例,仅 pg_reload_conf() 无效):

-- 超级用户执行
ALTER SYSTEM SET max_prepared_transactions = 100;

然后重启 PostgreSQL。Docker 示例:

docker restart <postgres容器名>
# 或创建容器时:
# docker run ... postgres:15 -c max_prepared_transactions=100

2. 验证:

SHOW max_prepared_transactions;  -- 必须为非 0,例如 100

3. 可选排查:

SELECT * FROM pg_prepared_xacts;  -- 查看未完成的预备事务

12.3 示例

private readonly IEasyCoreDtmXa _xa;

[HttpPost("SubmitXa")]
public async Task<IActionResult> Submit(CancellationToken ct)
{
    var result = await _xa.ExecuteGlobalAsync(async xa =>
    {
        await xa.CallBranchAsync(new { Amount = 30 }, "http://localhost:5039/api/Xa/Out", ct);
        await xa.CallBranchAsync(new { Amount = 30 }, "http://localhost:5039/api/Xa/In", ct);
    }, ct);

    return Ok(result.ToResponseBody());
}

[HttpPost("Out")]
public async Task<IActionResult> Out(CancellationToken ct)
{
    var result = await _xa.ExecuteLocalAsync(Request.Query, async conn =>
    {
        // 使用 conn 执行业务 SQL
        await Task.CompletedTask;
    }, ct);

    return Ok(result.ToResponseBody());
}

13. 数据库配置详解

🐬 MySQL

options.EasyCoreDtmMySql(mysql =>
{
    mysql.ConnectionString =
        "server=localhost;port=3306;user id=root;password=***;database=EasyCoreDtm";
    mysql.DtmDataBase = "EasyCoreDtm"; // → BarrierSqlTableName = EasyCoreDtm.barrier
});

DDL 对齐官方 dtmcli.barrier.mysql.sql。

🐘 PostgreSQL

options.EasyCoreDtmPostgreSql(pg =>
{
    pg.ConnectionString =
        "Host=localhost;Port=5432;Database=postgres;Username=postgres;Password=***";
    pg.Schema = "dtm_barrier"; // → dtm_barrier.barrier,约束名 uniq_barrier
});

DDL 对齐官方 dtmcli.barrier.postgres.sql,约束名必须为 uniq_barrier。

若使用 XA,还需配置 max_prepared_transactions > 0 并重启,详见 12.2 PostgreSQL XA 数据库设置。

🟦 SQL Server

options.EasyCoreDtmSqlServer(sql =>
{
    sql.ConnectionString =
        "Server=.;Database=EasyCoreDtm;User Id=sa;Password=***;TrustServerCertificate=True;";
    sql.DtmDataBase = "EasyCoreDtm"; // → [EasyCoreDtm].[dbo].[barrier]
});

唯一索引使用 IGNORE_DUP_KEY = ON(等价 MySQL INSERT IGNORE)。

⚠️ SQL Server 仅支持 Msg / TCC / Saga 的 barrier。IEasyCoreDtmXa 在 DatabaseType = SqlServer 时会抛 NotSupportedException(DtmCommon 无 SQL Server XA 方言)。

生产建表建议

options.AutoCreateBarrierTable = false; // 生产关闭自动 DDL

通过迁移流水线执行官方 / 本库 DDL,或预发生成后固化脚本。


14. API 一览

接口 主要方法
IEasyCoreDtmMsg DoAndSubmitAsync · SubmitWaitResultAsync · QueryPreparedAsync · CallBranchAsync
IEasyCoreDtmTcc CallBranchAsync · TransSucceedResponseAsync · TransFailureResponseAsync
IEasyCoreDtmSaga SubmitAsync · SubmitWaitResultAsync · SubmitConcurrentAsync · 成功/失败响应
IEasyCoreDtmXa ExecuteGlobalAsync · ExecuteLocalAsync · 成功/失败响应
DtmResult Success() / Failure() / ToResponseBody() → { dtm_result }

15. Demo 项目

项目 说明 命令
Web.EasyCore.DistributedTransaction.SqlServer Msg / TCC / Saga / XA Controllers + Swagger 见下方
# 先启动 DTM Server(:36789)与对应数据库
dotnet run --project demo/Web.EasyCore.DistributedTransaction.SqlServer
# 打开 Swagger,默认端口见 launchSettings

在 Program.cs 中切换 MySQL / PostgreSQL / SQL Server 注册即可。


16. 从 8.0 迁移

8.1.0 为破坏性升级:

旧版(8.0) 8.1
服务继承 ControllerBase,返回 IActionResult 返回 DtmResult,由 Controller 包装
MsgDoAndSubmitAsync / MsgQueryPreparedAsync(..., bool state) DoAndSubmitAsync / QueryPreparedAsync(无 state)
EasyCoreDtmSqlService / 包名 SqlService EasyCoreDtmSqlServer / 包名 SqlServer
DateBaseType DatabaseType
同步 Action 回调 Func<DbTransaction, Task>
无 XA IEasyCoreDtmXa
无 PostgreSQL 包 .PostgreSQL

17. 生产清单

  • DTM Server 高可用部署,业务配置正确的 DtmUrl
  • AutoCreateBarrierTable = false,使用评审后的迁移脚本
  • 连接串放入配置中心 / 密钥库
  • Msg:QueryPrepared URL 公网可达(或内网互通)
  • Saga / TCC 分支务必返回正确的 dtm_result
  • XA 仅在 MySQL / PostgreSQL 使用;SQL Server 不要调用 XA API
  • PostgreSQL XA:max_prepared_transactions > 0 且已重启;SHOW max_prepared_transactions 验证
  • MySQL XA:MySQL < 8.0 注意关闭连接池(上游限制)
  • SQL Server 确认 barrier 唯一索引含 IGNORE_DUP_KEY = ON
  • 运行 dotnet test 保障契约测试通过

18. FAQ

Q: QueryPrepared 总是 FAILURE?
A: 8.1 起按 barrier 真实结果返回。请确认本地 DoAndSubmit 已成功写入屏障,且未误用旧版 state: false。

Q: SQL Server 能用 XA 吗?
A: 不能。 本库与 DtmCommon 均不支持 SQL Server XA。注册 EasyCoreDtmSqlServer 后调用 IEasyCoreDtmXa 会抛 NotSupportedException: XA is not supported for 'SqlServer'。请改用 Msg / TCC / Saga,或将提供程序换为 MySQL / PostgreSQL。

Q: PostgreSQL XA 报 prepared transactions are disabled?
A: 执行 ALTER SYSTEM SET max_prepared_transactions = 100; 后重启 PostgreSQL,再用 SHOW max_prepared_transactions; 确认非 0。详见 12.2。

Q: PostgreSQL 报 unique constraint 相关错误?
A: 约束名必须是 uniq_barrier(Constant.Barrier.PG_CONSTRAINT)。请使用本库 DDL 或官方 postgres barrier 脚本。

Q: 为什么核心包没有 MySqlConnector?
A: 驱动下沉到提供程序包,避免多驱动冲突;通过 IDtmDbConnectionFactory 创建连接。

Q: Oracle 支持吗?
A: 上游 DtmCommon 1.4 无 Oracle 方言,本库不提供。


19. License

MIT — 详见 LICENSE 与 NuGet PackageLicenseExpression。


🤝 贡献

  1. Fork 并创建特性分支
  2. 在 tests/EasyCore.DistributedTransaction.DTM.Tests 补充测试
  3. 执行 dotnet test 与 dotnet build EasyCore.DistributedTransaction.DTM.sln
  4. 提交 Pull Request

欢迎 Issue / PR 🚀

Product Compatible and additional computed target framework versions.
.NET net8.0 is compatible.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 was computed.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 was computed.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages (4)

Showing the top 4 NuGet packages that depend on EasyCore.DistributedTransaction.DTM:

Package Downloads
EasyCore.DistributedTransaction.DTM.MySql

.Net Core DistributedTransaction with DTM - MySQL provider

EasyCore.DistributedTransaction.DTM.SqlService

.Net Core DistributedTransaction with DTM

EasyCore.DistributedTransaction.DTM.SqlServer

.Net Core DistributedTransaction with DTM - SQL Server provider

EasyCore.DistributedTransaction.DTM.PostgreSQL

.Net Core DistributedTransaction with DTM - PostgreSQL provider

GitHub repositories

This package is not used by any popular GitHub repositories.