Skip to content

jsrdxzw/dtm-spring-boot-starter

Repository files navigation

license Build Status

English | 简体中文

dtm-spring-boot-starter

dtm-spring-boot-starter is java sdk based on spring boot for dtm, spring boot 2.x version is required.

Now this sdk supports following distributed transaction features:

  1. TCC
  2. Saga
  3. two-phase commit

Quick Start

  1. pom file
<dependency>
    <groupId>com.jsrdxzw.github</groupId>
    <artifactId>dtm-spring-boot-starter</artifactId>
    <version>1.1.0</version>
</dependency>
  1. dtm server configuration
dtm:
  http-server: http://localhost:36789/api/dtmsvr # dtm server address

# your project configuration
spring:
   datasource:
      driver-class-name: com.mysql.cj.jdbc.Driver
      username:
      password:
      url: jdbc:mysql://localhost:3306/{project}
  1. execute sql files in dtm
    1. dtmcli.barrier.mysql.sql.
    2. If you want to use barrier,create barrier table using dtmsvr.storage.mysql.sql.
  2. use @EnableDtm to start auto-configuration in spring boot.
@SpringBootApplication
@EnableDtm
public class DtmSpringBootExampleApplication {
    public static void main(String[] args) {
        SpringApplication.run(DtmSpringBootExampleApplication.class, args);
    }
}

Saga

AP Usage

public void doSomething() {
     TransReq req = new TransReq();
     req.setAmount(BigDecimal.valueOf(100));
     DtmServerResult result = new Saga(httpClient)
                                   .add(HOST + "/SagaBTransOut", HOST + "/SagaBTransOutCom", req)
                                   .add(HOST + "/SagaBTransIn", HOST + "/SagaBTransInCom", req)
                                   .submit(); 
}

DM Usage

@DtmResponse
@PostMapping("/SagaBTransOut")
public ResultData sagaTransOut(@DtmBarrier BranchBarrier branchBarrier, @RequestBody TransReq transReq) throws Exception {
   branchBarrier.call(transactionManager, barrier -> {
      userAccountMapper.sagaAdjustBalance(TRANSOUT_UID, transReq.getAmount().negate());
   });
   return ResultData.success();
}

@DtmResponse
@PostMapping("/SagaBTransIn")
public ResultData sagaTransIn(@DtmBarrier BranchBarrier branchBarrier, @RequestBody TransReq transReq) throws Exception {
   branchBarrier.call(transactionManager, barrier -> {
       userAccountMapper.sagaAdjustBalance(TRANSIN_UID, transReq.getAmount());
   });
   return ResultData.success();
}

@DtmResponse
@PostMapping("/SagaBTransOutCom")
public ResultData sagaTransOutCom(@DtmBarrier BranchBarrier branchBarrier, @RequestBody TransReq transReq) throws Exception {
   branchBarrier.call(transactionManager, barrier -> {
        userAccountMapper.sagaAdjustBalance(TRANSOUT_UID, transReq.getAmount());
   });
   return ResultData.success();
}

@DtmResponse
@PostMapping("/SagaBTransInCom")
public ResultData sagaTransInCom(@DtmBarrier BranchBarrier branchBarrier, @RequestBody TransReq transReq) throws Exception {
   branchBarrier.call(transactionManager, barrier -> {
        userAccountMapper.sagaAdjustBalance(2, transReq.getAmount().negate());
   });
   return ResultData.success();
}

Tcc

AP Usage

public void doSomething() {
     TransReq transReq = TransReq.builder().amount(BigDecimal.valueOf(30)).build();
     new Tcc(httpClient).tccGlobalTransaction(tcc -> {
        tcc.callBranch(
            transReq, HOST + "/tccTransOutTry", HOST + "/tccTransOutConfirm", HOST + "/tccTransOutCancel");
        tcc.callBranch(
            transReq, HOST + "/tccTransInTry", HOST + "/tccTransInConfirm", HOST + "/tccTransInCancel");
     });
}

DM Usage

@DtmResponse
@PostMapping("/tccTransInTry")
public ResultData tccTransInTry(@DtmBarrier BranchBarrier branchBarrier, @RequestBody TransReq transReq) throws Exception {
     branchBarrier.call(transactionManager, barrier -> {
         userAccountMapper.tccAdjustTrading(TRANSIN_UID, transReq.getAmount());
     });
     return ResultData.success();
}
@DtmResponse
@PostMapping("/tccTransInConfirm")
public ResultData tccTransInConfirm(@DtmBarrier BranchBarrier branchBarrier, @RequestBody TransReq transReq) throws Exception {
   branchBarrier.call(transactionManager, barrier -> {
        userAccountMapper.tccAdjustBalance(TRANSIN_UID, transReq.getAmount());
   });
   return ResultData.success();
}

@DtmResponse
@PostMapping("/tccTransInCancel")
public ResultData tccTransInCancel(@DtmBarrier BranchBarrier branchBarrier, @RequestBody TransReq transReq) throws Exception {
     branchBarrier.call(transactionManager, barrier -> {
        userAccountMapper.tccAdjustTrading(TRANSIN_UID, transReq.getAmount().negate());
     });
     return ResultData.success();
}

// ...

two-phase commit

public void doSomething() {
     TransReq req = TransReq.builder().amount(BigDecimal.valueOf(30)).build();
     Msg msg = new Msg(httpClient).add(HOST + "/SagaBTransOut", req).add(HOST + "/SagaBTransIn", req);
     msg.prepare(HOST + "/query");
     // ... your business logic
     msg.submit();
}

commit and query

@GetMapping("/query")
public DtmServerResult queryDtm(@DtmBarrier BranchBarrier branchBarrier) {
     branchBarrier.queryPrepared(transactionManager);
     DtmServerResult dtmServerResult = new DtmServerResult();
     dtmServerResult.setResult(DtmResultEnum.SUCCESS);
     return dtmServerResult;
}

@PostMapping("/http_msg_doAndCommit")
public String httpMsgDoAndCommit() {
     TransReq req = TransReq.builder().amount(BigDecimal.valueOf(200)).build();
     Msg msg = new Msg(dtmHttpClient).add(host + "/SagaBTransIn", req);
     msg.doAndSubmitDb(transactionManager, host + "/query", barrier -> {
        System.out.println("submit transout");
        userAccountMapper.sagaAdjustBalance(TRANSOUT_UID, req.getAmount().negate());
     });
     return "ok";
}

more examples

please see dtm-spring-boot-starter examples to learn more details.