老板现在喊我大哥,原因是我用阿里分布式事务框架Seata解决了长久以来困扰公司的分布式事务问题

Posted java1234_小锋

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了老板现在喊我大哥,原因是我用阿里分布式事务框架Seata解决了长久以来困扰公司的分布式事务问题相关的知识,希望对你有一定的参考价值。

大家好,我是曹尼玛

从大学毕业5年,一直努力学习,努力工作,追求新技术,不保守。

上个月我来到一家新公司上班,月薪20K,这家公司老板人很好,对员工很关爱,公司氛围不错,同事们也努力把公司项目搞搞好。除了那个混日子的10年开发经验的老王(老板小舅子)

由于老板对客户比较负责,业界口碑好,公司的项目越做越大,单子也越来越多,但是很多客户项目要求分布式微服务,因为大部分是金融外贸项目,搞了微服务后,偶尔出现分布式事务不一致性问题,客户很是反感,前段时间,公司用TCC试水,发现这个方案代码侵入性太强,维护也不方便,人工投入太大,也容易编码出错。

后来用基于RocketMQ消息队列实现可靠消息最终一致性方案代替,能实现要求,比TCC好维护点,但是实现起来,终究得依赖消息中间件,而且逻辑也有点繁琐,公司项目涉及到得分布式事务模块还是很多的,搞得天罗地网似的。

公司急于寻求一种简单快捷高效的低代码侵入式的分布式事务解决方案。

作为新技术控,我一直关注新技术,最近2年,阿里分布式事务解决方案Seata很火,人气很足!

也深入研究过,现在最新版本1.4.2,基本成熟了,可以商用!作为Spring Cloud Alibaba服务组件,很好集成到项目里,而且我都深入测试过!
所以我鼓起勇气,直接走到老板办公室,让老板试试 Seata 吧;

老板不是一个思想保守的人,乐于尝试!他说他先研究下Seata。

第二天,老板叫我进办公室,直接说“公司的438项目,有一个sb模块涉及分布式事务,你用seata搞下”。我连忙说”OK,没问题,保证完成任务“!

由于我对seata比较熟悉,MD笔记整理得井井有条。所以一顿猛操,seata-server配置下,启动,微服务项目applicaton.yml配置下,@GlobalTransactional加上,测试下,没问题,一上午就撸完了,跟老板说”可以让测试部的小姐姐测试下了“。

老板惊呆了,这么快就搞完了?半信半疑

下午测试部的小姐姐们仔细功能测试,压测,没毛病!偶尔服务调用超时也是自动回滚事务,所以不影响业务,界面有友好用户提示”系统繁忙,请稍后重试“!

老板听到测试部的汇报后,直接让版本更新放到线上让客户使用!
用了一个多月,根据客户反馈,以及日志系统查看,这次seata解决方案非常OK!

老板让漂亮的小秘把我叫到办公室,然后塞给我一沓厚厚的信封,跟我说 ”曹大哥,明天开始,那个混饭吃胡日子不思进取的10年经验的老王就要滚蛋了,以后技术总监的位置就是你的了,薪资是40K,15薪资+项目奖金+年终奖“,”另外还有特殊福利“,顺便喵看了下旁边芳龄18的小敏秘书!

由于我过于激动,那天说话老是合不拢嘴!

3年以后,我成为了公司技术一把手,年入百万;
第4年,我当爸爸了,选了个风和日丽的日子,开着保时捷Panamera,带着满月的儿子和小敏一起去拍满月照!


阿里Seata作为一个优秀得分布式事务解决方案,让穷屌丝的我逆袭了,我决定公开我的seata笔记,顺便还录制了一套Seata视频教程,希望对大家有帮助!

1 阿里分布式事务框架Seata简介

Seata 是一款开源的分布式事务解决方案,致力于提供高性能和简单易用的分布式事务服务。Seata 将为用户提供了 AT、TCC、SAGA 和 XA 事务模式,为用户打造一站式的分布式解决方案。

中文官方站点:https://seata.io/zh-cn/

seata github开源地址:https://github.com/seata

2 分布式事务简介

2.1 本地事务

在计算机系统中,更多的是通过关系型数据库来控制事务,这是利用数据库本身的事务特性来实现的,因此叫数据库事务,由于应用主要靠关系数据库来控制事务,而数据库通常和应用在同一个服务器,所以基于关系型数据库的事务又被称为本地事务。

数据库事务的四大特性:ACID

A(Atomic):原子性,构成事务的所有操作,要么都执行完成,要么全部不执行,不可能出现部分成功部分失败的情况。

C(Consistency):一致性,在事务执行前后,数据库的一致性约束没有被破坏。比如:张三向李四转 100 元,转账前和转账后的数据是正确状态这叫一致性,如果出现张三转出 100 元,李四账户没有增加 100 元这就出现了数 据错误,就没有达到一致性。

I(Isolation):隔离性,数据库中的事务一般都是并发的,隔离性是指并发的两个事务的执行互不干扰,一个事务不能看到其他事务的运行过程的中间状态。通过配置事务隔离级别可以比避免脏读、重复读问题。

D(Durability):持久性,事务完成之后,该事务对数据的更改会持久到数据库,且不会被回滚。

数据库事务在实现时会将一次事务的所有操作全部纳入到一个不可分割的执行单元,该执行单元的所有操作要么都成功,要么都失败,只要其中任一操作执行失败,都将导致整个事务的回滚。

2.2 分布式事务

随着互联网的快速发展,软件系统由原来的单体应用转变为分布式应用

分布式系统会把一个应用系统拆分为可独立部署的多个服务,因此需要服务与服务之间远程协作才能完成事务操作,这种分布式系统环境下由不同的服务之间通过网络远程协作完成事务称之为分布式事务,例如用户注册送积分事务、创建订单减库存事务,银行转账事务等都是分布式事务。

3 SpringCloud Alibaba分布式基础案例搭建

我们模拟一个简单下单业务,客户端调用rest对外服务,rest服务再调用订单服务实现创建订单和账户服务实现账户扣钱操作,最终来完整下单业务;

2.1 案例架构设计

所有服务都注册到nacos中,方便feign远程调用;订单服务,账户服务各自有独立数据库;架构设计如下图:

整体项目结构如下图:

seatatest是父项目,主要是做一些依赖管理,依赖版本管理,管理所有子module项目;

seata-common子项目,主要是引入其他子项目需要的公共依赖,以及公共实体,工具类,配置类的统一封装;

seata-order子项目,主要提供订单服务,生成订单;

seata-account子项目,主要提供账户服务,根据订单扣钱操作;

seata-web子项目,主要处理客户端下单请求,feign远程调用order,和account服务接口,最终完成下单处理;

2.2 数据库设计

我们新建两个数据库,分别是db_order(订单数据库),db_account(账户数据库),

db_order数据库里面新建表t_order订单表:

CREATE TABLE `t_order` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `orderNo` varchar(100) DEFAULT NULL,
  `userId` int(11) DEFAULT NULL,
  `count` int(11) DEFAULT NULL,
  `amount` int(11) DEFAULT NULL,
  `remark` varchar(100) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=21 DEFAULT CHARSET=utf8

db_account数据库里面新建表t_account用户账户表:

CREATE TABLE `t_account` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `userId` int(11) DEFAULT NULL,
  `balance` int(11) DEFAULT NULL,
  `remark` varchar(100) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8

插入数据:

insert into `t_account` (`id`, `userId`, `balance`, `remark`) values('1','1','2000','jack的账户');
insert into `t_account` (`id`, `userId`, `balance`, `remark`) values('2','2','1000','marry的账户');

2.3 seatatest父项目搭建

seatatest是父项目,主要是做一些依赖管理,依赖版本管理,管理所有子module项目;

注意,它的packaging类型是pom

pom.xml:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.java1234</groupId>
    <artifactId>seatatest</artifactId>
    <packaging>pom</packaging>
    <version>1.0-SNAPSHOT</version>
    <modules>
        <module>seata-common</module>
        <module>seata-order</module>
        <module>seata-account</module>
        <module>seata-web</module>
    </modules>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
        <druid.version>1.1.10</druid.version>
        <spring-cloud.version>Hoxton.SR8</spring-cloud.version>
        <springboot.version>2.3.2.RELEASE</springboot.version>
        <springcloudalibaba.version>2.2.4.RELEASE</springcloudalibaba.version>
        <fastjson.version>1.2.35</fastjson.version>
        <commons-lang3.version>3.6</commons-lang3.version>
        <seata-common.version>1.0-SNAPSHOT</seata-common.version>
        <mybatis.version>2.1.0</mybatis.version>
    </properties>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${spring-cloud.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-dependencies</artifactId>
                <version>${springboot.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <dependency>
                <groupId>com.alibaba.cloud</groupId>
                <artifactId>spring-cloud-alibaba-dependencies</artifactId>
                <version>${springcloudalibaba.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <!-- 连接池 -->
            <dependency>
                <groupId>com.alibaba</groupId>
                <artifactId>druid</artifactId>
                <version>${druid.version}</version>
            </dependency>

            <dependency>
                <groupId>com.alibaba</groupId>
                <artifactId>fastjson</artifactId>
                <version>${fastjson.version}</version>
            </dependency>

            <dependency>
                <groupId>org.apache.commons</groupId>
                <artifactId>commons-lang3</artifactId>
                <version>${commons-lang3.version}</version>
            </dependency>

            <dependency>
                <groupId>com.java1234</groupId>
                <artifactId>seata-common</artifactId>
                <version>${seata-common.version}</version>
            </dependency>

            <dependency>
                <groupId>org.mybatis.spring.boot</groupId>
                <artifactId>mybatis-spring-boot-starter</artifactId>
                <version>${mybatis.version}</version>
            </dependency>

        </dependencies>
    </dependencyManagement>


    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>


</project>

2.4 seata-common子项目搭建

seata-common子项目,主要是引入其他子项目需要的公共依赖,以及公共实体,工具类,配置类的统一封装;

项目结构:

pom.xml:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>seatatest</artifactId>
        <groupId>com.java1234</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>seata-common</artifactId>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>

        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
        </dependency>


        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
        </dependency>

        <!-- spring boot redis 缓存引入 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>
        <!-- lettuce pool 缓存连接池 -->
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-pool2</artifactId>
        </dependency>

        <dependency>
            <groupId>com.alibaba</groupId>
            <以上是关于老板现在喊我大哥,原因是我用阿里分布式事务框架Seata解决了长久以来困扰公司的分布式事务问题的主要内容,如果未能解决你的问题,请参考以下文章

阿里分布式事务seata入门(采坑)

老板发了我2千奖金,原因是我用Java实现了管理员可以修改任意用户Session的功能

真赞!阿里开源的这款分布式事务框架

燃!阿里开源分布式事务框架!!!

阿里分布式事务框架 GTS 全解析

详解阿里开源分布式事务框架Seata