EasyCore.DistributedTransaction.DTM.MySql 8.1.0

There is a newer version of this package available.
See the version list below for details.
dotnet add package EasyCore.DistributedTransaction.DTM.MySql --version 8.1.0
                    
NuGet\Install-Package EasyCore.DistributedTransaction.DTM.MySql -Version 8.1.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.MySql" Version="8.1.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="EasyCore.DistributedTransaction.DTM.MySql" Version="8.1.0" />
                    
Directory.Packages.props
<PackageReference Include="EasyCore.DistributedTransaction.DTM.MySql" />
                    
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.MySql --version 8.1.0
                    
#r "nuget: EasyCore.DistributedTransaction.DTM.MySql, 8.1.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.MySql@8.1.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.MySql&version=8.1.0
                    
Install as a Cake Addin
#tool nuget:?package=EasyCore.DistributedTransaction.DTM.MySql&version=8.1.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.EasyCoreDistributedTransactionDtm(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 OR Apache-2.0 — 详见 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

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.