# golang dtm server
```go=
git clone https://github.com/dtm-labs/dtm && cd dtm
go run main.go
git clone https://github.com/dtm-labs/dtmcli-go-sample && cd dtmcli-go-sample
go run main.go
```
```go=
// QsFireRequest quick start: fire request
func QsFireRequest() string {
fmt.Println(mount)
req := &gin.H{"amount": 30} // 微服務的載荷
// DtmServer為DTM服務的地址
saga := dtmcli.NewSaga(dtmServer, dtmcli.MustGenGid(dtmServer)).
// 添加一個TransOut的子事務,正向操作為url: qsBusi+"/TransOut", 逆向操作為url: qsBusi+"/TransOutCompensate"
Add(qsBusi+"/TransOut", qsBusi+"/TransOutCompensate", req).
// 添加一個TransIn的子事務,正向操作為url: qsBusi+"/TransOut", 逆向操作為url: qsBusi+"/TransInCompensate"
Add(qsBusi+"/TransIn", qsBusi+"/TransInCompensate", req)
// 提交saga事務,dtm會完成所有的子事務/回滾所有的子事務
err := saga.Submit()
logger.FatalIfError(err)
return saga.Gid
}
```
```go=
var mount = 30
func qsAddRoute(app *gin.Engine) {
app.POST(qsBusiAPI+"/TransIn", func(c *gin.Context) {
logger.Infof("TransIn")
// c.JSON(200, "")
mount += 60
fmt.Println(mount)
c.JSON(409, "") // Status 409 for Failure. Won't be retried
})
app.POST(qsBusiAPI+"/TransInCompensate", func(c *gin.Context) {
logger.Infof("TransInCompensate")
mount -= 60
fmt.Println(mount)
c.JSON(200, "")
})
app.POST(qsBusiAPI+"/TransOut", func(c *gin.Context) {
logger.Infof("TransOut")
mount -= 20
fmt.Println(mount)
c.JSON(200, "")
})
app.POST(qsBusiAPI+"/TransOutCompensate", func(c *gin.Context) {
logger.Infof("TransOutCompensate")
mount += 20
fmt.Println(mount)
c.JSON(200, "")
})
}
```
當你的微服務都是http requset 則在
```go=
Add(qsBusi+"/TransOut", qsBusi+"/TransOutCompensate", req).
// 添加一個TransIn的子事務,正向操作為url: qsBusi+"/TransOut", 逆向操作為url: qsBusi+"/TransInCompensate"
Add(qsBusi+"/TransIn", qsBusi+"/TransInCompensate", req)
```
要確保這部分的業務邏輯一定要對否則rollback
```go=
app.POST(qsBusiAPI+"/TransIn", func(c *gin.Context) {
logger.Infof("TransIn")
// c.JSON(200, "")
mount += 60
fmt.Println(mount)
c.JSON(409, "") // Status 409 for Failure. Won't be retried
})
```
可以看到最終值可以維持不變
![](https://i.imgur.com/HDFUvBE.png)