A, requirements,

The Transactional Spring local transaction @Transactional does not solve the problem of ensuring data consistency across libraries and services. Distributed transactions generally include transaction initiator and participant, relational database resource service and transaction manager. The most popular Distributed Transaction frameworks are TX-LCN and Alibaba’s SEATA Framework, which will be investigated in the next article.

Tx-lcn distributed transaction framework is an open source distributed transaction framework, which consists of two modules: TxClient and TxManager. TxClient acts as initiator and participant, and TxManager acts as transaction manager to coordinate transactions. From the perspective of development, TxClient refers to our own service system, TxManager is the coordination system of the transaction center; Github RELEASE version 5.0.2.RELEASE (LCN TXC TCC transaction mode is supported). The project uses V4.1.0 for stability (LCN mode is only supported by default). The basic principle of the LCN mode is that the proxy section intercepts the commit and rollback of all database links, and the proxy connection object controls the actual commit, rollback and release of local transactions. If there is a non-relational database REDis, TCC mode compensation operation is needed to ensure the overall consistency of non-relational REDis and relational mysql.

Two, start preparing

1, prepare mysql and Redis environment, passspring initializrQuick preparation of the Eureka registry.

2, downloadv4.1.0Version, tx – LCN – 4.1.0 is spring boot program requires eureka registry services and redis, run to start the class com. Codingapi. Tm. TxManagerApplication.

3, access,http://127.0.0.1:8899/TxManager management interface, pay attention to the two attributes of load balancing server address port and the current connection number, this is the successful experiment screenshot, at the beginning of the current connection number should be 0.

4,Springcloud LCN Distributed Transaction V4.0 example demo

Follow the instructions to create the database and modify the configuration, highlighting important configurations. We focus on the JDBC version of SpringCloud-JDBC-Demo, which involves 5 service modules, project from 1 to 5 corresponding port: 8081 to 8085, the controller interface prefix is localhost:port/demo, divided into list interface and save interface; In the save method, demo3 (calling 4 and 5, itself) and DEMO1 (calling 2 and 3, itself) are the transaction initiator. The difference between demo3 and DEMO1 is that demo3 annotates the exception and can normally return insert data, while DEMO1 opens the exception and triggers the distributed transaction to roll back INSERT data. Demo2, DEMO4, and DEMO5 are only transaction participants.

feign.hystrix.enabled=false spring.datasource.driver-class-name = com.mysql.jdbc.Driver spring.datasource.url= jdbc:mysql://localhost:3306/test spring.datasource.username= root spring.datasource.password=root spring.datasource.initialize = true init-db= true spring.application.name = demo3 server.port = 8083 9 # ${random. Int [9000999]}. Registry port to corresponding eureka. Client. The service - url. DefaultZone = http://127.0.0.1:8761/eureka/ feign. Hystrix. Enabled = true # About ** SpringCloud-Hystrix mechanism, Select signal isolation * * mand http://www.jianshu.com/p/b8d21248c9b1 hystrix.com. Default. Execution. The isolation. The strategy = SEMAPHORE Hystrix.com mand. Default. Execution. The isolation. Thread. TimeoutInMilliseconds = 5000 # Ribbon load balancing strategy, Retry count of 0 ribbon.NFLoadBalancerRuleClassName=com.net flix. Loadbalancer. RandomRule ribbon. MaxAutoRetriesNextServer = 0 # * * txmanager address port is txmanager management interface port of load balancing server address * * tm manager. Url = http://127.0.0.1:8899/tx/manager/ logging.level.com.codingapi=debugCopy the code

For example, @txTransaction (isStart = true) indicates the transaction initiator. Otherwise, ThreadLocal will not have groupid, so there will be no transaction group, and rollback transaction will not be possible.

GroupId is empty if an exception occurs on the unmarked initiator:

2020-05-30 17:30:06.387 DEBUG 4964 --- [nio-8084-exec-8] c.c.t.s.interceptor.TransactionAspect    : annotation-TransactionRunning-start---->
2020-05-30 17:30:06.387 DEBUG 4964 --- [nio-8084-exec-8] c.c.t.a.s.impl.AspectBeforeServiceImpl   : around--> groupId-> null,txTransactionLocal->null
2020-05-30 17:30:06.387 DEBUG 4964 --- [nio-8084-exec-8] c.c.t.d.aspect.DataSourceAspect          : getConnection-start---->
2020-05-30 17:30:06.387 DEBUG 4964 --- [nio-8084-exec-8] c.c.tx.datasource.AbstractResourceProxy  : loadConnection -> null !
Copy the code

DemoServiceImpl

package com.example.demo.service.impl;

import com.example.demo.client.Demo2Client;
import com.example.demo.client.Demo3Client;
import com.example.demo.dao.TestDao;
import com.example.demo.entity.Test;
import com.example.demo.service.DemoService;
import com.codingapi.tx.annotation.TxTransaction;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;

/** * Created by lorne on 2017/6/26. */
@Service
public class DemoServiceImpl implements DemoService {

    @Autowired
    private TestDao testDao;

    @Autowired
    private Demo2Client demo2Client;

    @Autowired
    private Demo3Client demo3Client;

    @Override
    public List<Test> list(a) {
        return testDao.list();
    }

    @Override支那@TxTransaction(isStart = true) * *@Transactional
    public int save(a) {

        int rs2 = demo2Client.save();

        int rs3 = demo3Client.save();

        int rs1 = testDao.save();

        int v = 100/0;

        returnrs1+rs2+rs3; }}Copy the code

Access the Save interface of Demo1

/ / access the save interface: http://localhost:8081/demo/save, trigger the exception
Whitelabel Error Page
This application has no explicit mapping for /error, so you are seeing this as a fallback.

Sat May 30 17:33:11 CST 2020
There was an unexpected error (type=Internal Server Error, status=500).
Demo3Client#save(a) failed and fallback failed.
Copy the code

Trigger rollback JdbcDemo2Application console correct log:

# trigger a rollback for the 2020-05-30 17:33:11. 654 the DEBUG 4468 - c.c.tx.net ty [ntLoopGroup - 2-1]. The handler. TransactionHandler: TxManager - response - > {" a ":" t ", "c" : 0, "t" : "9 fxhh19m", "k" : "62 KQVGPH"} 17:33:11 2020-05-30. 4468-654 the INFO [ool-1-thread-19] c.c.t.c.service.impl.ActionTServiceImpl : accept notify data ->{"a":"t","c":0,"t":"9Fxhh19M","k":"62kQVGPh"} lcn transaction over, Res -> groupId: rollback 2020-05-30 17:33:11.657 DEBUG 4468 -- [thread-28] c.c.t.d.relational.LCNDBConnection : LcnConnection Closed groupId:3OBwlhvN 2020-05-30 17:33:11.658 INFO 4468 -- [OOL-1-thread-19] c.c.t.c.service.impl.ActionTServiceImpl : Accept notify Response RES ->1 2020-05-30 17:33:11.658 DEBUG 4468 -- [OOL-1-thread-19] .c.t.c.s.i.TransactionControlServiceImpl : Send notify data - > {" p ": {" d" : "1"}, "a" : "t", "k" : "62 KQVGPH"} 17:33:11 2020-05-30. 4468-659 the DEBUG] [ntLoopGroup - 2-1 c.c.tx.netty.handler.TransactionHandler : Txmanager-response ->{"d":"","k":"62kQVGPh"} # txManager-response ->{"d":"","k":"62kQVGPh"}  c.c.tx.netty.handler.TransactionHandler : Hart data - > {" p ":" {} ", "a" : "h", "k" : "h"} 17:33:26 2020-05-30. 4468-659 the DEBUG] [ntLoopGroup - 2-1 c.c.tx.netty.handler.TransactionHandler : TxManager-response->{"d":"5","k":"h"}Copy the code

Iii. Differences between version 4.0 and 5.0

Version 5.0 has been submitted in bulk since January and has been developed and maintained by the codingApi team. The annotated source code for the two versions is different.

/** ** version 4.0 ** * Created by Lorne on 2017/6/26. */
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface TxTransaction {

    /** * Whether to initiate the LCN transaction *@returnTrue: Indicates the initiator. False: Indicates the participant */
    boolean isStart(a) default false;

    /** * Rollback exception *@return* /
    Class<? extends Throwable>[] rollbackFor() default {};

    /** * Does not roll back exceptions *@return* /
    Class<? extends Throwable>[] noRollbackFor() default {};

}
Copy the code
/**** version 5.0 *** Created by Lorne on 2017/6/26. */
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface TxTransaction {

    /** * Transaction type **@return lcn, tcc, txc
     * @see Transactions
     */
    String type(a) default Transactions.LCN;

    /** * Distributed transaction propagation behavior **@returnCommunication behavior@see DTXPropagation
     */
    DTXPropagation propagation(a) default DTXPropagation.REQUIRED;
}
Copy the code

Iv. Reference materials

  1. Distributed transactions from 0 to 1- Recognize distributed transactions
  2. codingapi/tx-lcn
  3. Springcloud LCN Distributed Transaction V4.0 example demo