EasyCore.DistributedTransaction.DTM.MySql
8.3.0
dotnet add package EasyCore.DistributedTransaction.DTM.MySql --version 8.3.0
NuGet\Install-Package EasyCore.DistributedTransaction.DTM.MySql -Version 8.3.0
<PackageReference Include="EasyCore.DistributedTransaction.DTM.MySql" Version="8.3.0" />
<PackageVersion Include="EasyCore.DistributedTransaction.DTM.MySql" Version="8.3.0" />
<PackageReference Include="EasyCore.DistributedTransaction.DTM.MySql" />
paket add EasyCore.DistributedTransaction.DTM.MySql --version 8.3.0
#r "nuget: EasyCore.DistributedTransaction.DTM.MySql, 8.3.0"
#:package EasyCore.DistributedTransaction.DTM.MySql@8.3.0
#addin nuget:?package=EasyCore.DistributedTransaction.DTM.MySql&version=8.3.0
#tool nuget:?package=EasyCore.DistributedTransaction.DTM.MySql&version=8.3.0
🔀 EasyCore.DistributedTransaction.DTM
EasyCore.DistributedTransaction.DTM 是面向 .NET 8 的生产级分布式事务客户端封装。基于开源 DTM 与 Dtmcli,提供 Msg / TCC / Saga / XA 四种模式、子事务屏障、以及 MySQL / PostgreSQL / SQL Server 独立 SQL 支持包。
🌍 Language
- 中文(当前文档)
- English: README.en.md
📚 目录
第一部分:总览与架构
第二部分:快速上手
第三部分:四种模式详解
第四部分:持久化与生产
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 组件关系图
2.2 四种模式一览
2.3 四种模式时序
📨 Msg
🧩 TCC
🔗 Saga
⚙️ XA
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:
QueryPreparedURL 公网可达(或内网互通) - 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。
🤝 贡献
- Fork 并创建特性分支
- 在
tests/EasyCore.DistributedTransaction.DTM.Tests补充测试 - 执行
dotnet test与dotnet build EasyCore.DistributedTransaction.DTM.sln - 提交 Pull Request
欢迎 Issue / PR 🚀
| Product | Versions 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. |
-
net8.0
- EasyCore.DistributedTransaction.DTM (>= 8.3.0)
- MySqlConnector (>= 2.4.0)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.