关于Seata

1.下载Seata

Releases · seata/seata · GitHub:fire: Seata is an easy-to-use, high-performance, open source distributed transaction solution. - Releases · seata/seatahttps://github.com/seata/seata/releases

https://github.com/seata/seata/releases/download/v1.4.2/seata-server-1.4.2.zipicon-default.png?t=M7J4https://github.com/seata/seata/releases/download/v1.4.2/seata-server-1.4.2.zip

2.什么是Seata

Seata 是一款开源的分布式事务解决方案,致力于在微服务架构下提供高性能和简单易用的分布式事务服务。是阿里的产品,官网:SeataSeata官网https://seata.io/zh-cn/

也是Spring Cloud Alibaba提供的组件。

3.为什么需要Seata

        3.1认识事务

        想认识Seata,我们先要来看下什么是事务。事务就是用户定义的一系列数据库操作,这些操作可以视为一个完整的逻辑处理工作单元,要么全部执行,要么全部不执行,是不可分割的工作单元。事务有四大特性ACID:

   (1) 原子性(Atomicity)

        事务的原子性保证事务中包含的一组更新操作是原子的,中早期物理学中原子单位是最小的单位,不可分割。在事务中,我们将事务操作视为一个整体,执行过程中遵循“要么全部执行,要不都不执行”,不存在一半执行,一半未执行的情况。

    (2)一致性(Consistency)      

        执行的结果必须是使数据库从一个一致性状态变到另一个一致性状态。因此当数据库只包含成功事务提交的结果时,就代表数据库处于一致性状态。

        如果数据库系统 运行中发生故障,有些事务尚未完成就被迫中断,这些未完成事务对数据库所做的修改有一部分已写入物理数据库,这时数据库就处于一种不正确的状态,或者说是 不一致的状态。

    (3)隔离性(Isolation)

扫描二维码关注公众号,回复: 15394541 查看本文章

        事务的隔离性要求事务之间是彼此独立的,隔离的。及一个事务的执行不可以被其他事务干扰。具体到操作是指一个事务的操作必须在一个事务commit之后才可以进行操作。多事务并发执行时,相当于将并发事务变成串行事务,顺序执行。

    (4)持续性(Durability)

        指一个事物一旦提交,它对数据库中数据的改变就应该是永久性的。接下来的其他操作或故障不应该对其有任何影响。

      3.2认识本地事务及管理方式

         在单体式架构中我们在同时执行两条紧密关联的数据库sql时,也就是满足原子性的两条sql时,比如增加订单 和 减少库存。这种事务我们称之为本地事务(Local Transaction )我们借助的是Spring内部的声明式事务:

        声明式的事务管理是基于AOP的,在springboot中可以通过@Transactional注解的方式获得支持,这种方式的优点是:

1.提供了注解@Transactional,来进行事务管理, 添加上该注解,开启事务管理的机制无需编码, 自动处理, 简化了事务处理编程!不同底层事务, 使用相同的注解@Transactional分布式事务, 也采用统一的注解 @Transactional在运行期,调用某个目标业务方法时,若检测到方法上有该注解,则开启事务管理,将切面中的通知代码织入到目标业务代码中,事务管理的通知是环绕通知。

Spring事务管理优势:

1.统一事务处理风格: 解决了持久层框架不同,使用API不同的问题--解决办法是通过平台事务管理器

2.使用AOP解决了代码重复问题,将事务管理的关注点代码提取到切面中,在运行期动态的进行织入

3.解决了全局事务和局部事务使用不同API的问题 通过事务管理器解决了以上问题 且全局事务和局部事务中,事务失败后,给出的处理方式是一样的

4.非侵入式,业务逻辑不受事务管理代码的污染。

5.方法级别的事务回滚,合理划分方法的粒度可以做到符合各种业务场景的事务管理。

 操作方法是:

        配置事务管理器: Spring Boot 中往往自动自动配置spring-boot-starter-jdbc 依赖中 就自动配置了JDBC事务管理器

        如果单独使用Spring, 则需要手动配置 事务管理器(JavaBean) @EnableTransactionManagement使用 @Transactional注解 标注需要事务处理的方法案例, 测试spring-boot-starter-jdbc自动配置的事务管理器:

@SpringBootTest
public class TxTests {
    Logger logger = LoggerFactory.getLogger(TxTests.class);
    @Autowired
    PlatformTransactionManager transactionManager;

    @Test
    void transactionManager(){
        /*
         * 测试spring-boot-starter-jdbc 自动配置的事务管理器
         */
        logger.debug("transactionManager: {}", transactionManager);
    }
}

@Transactional注解的用法

可以用于以下位置: 1. 业务方法上方 2. 业务层接口上方 -- 接口中的所有方法都开启事务管理 -- 从Spring5.0开始的 3. 业务类上方 -- 类中所有的方法都开启事务管理

注意点:在Spring项目中(不是SpringBoot),若要开启事务管理,必须在配置类的上方加注解@EnableTransactionManagement
测试事务注解, @Transactional 以后, 对象会被自动创建AOP 事务代理.
 

@Transactional
public Student regist(Student student) {
    if (student==null || student.getName()==null) {
        throw new IllegalParameterException("参数异常!");
    }
    Student stu = studentDao.findStudentByName(student.getName());
    if (stu!=null) {
        throw new UserNameIsUsedException("该账号已经被注册!");
    }
    int num = studentDao.saveStudent(student);
    if (num!=1) {
        throw new RegistFaildException("注册账号失败!");
    }
    return stu;
}
@Autowired
StudentService studentService;

@Test
void studentService(){
    logger.debug("{}", studentService.getClass().getName());
}

声明式事务管理原理

采用的AOP,在运行期会生成代理对象

业务方法中抛出运行时异常(RuntimeException),则事务回滚;若抛出的是检查异常,事务不会回

@Transactional注解的属性

timeout: 指定超时时间,单位s 默认值-1,表示永不超时 若同时在类上方和某个方法上方指定超时时间,则添加了该属性的方法的超时时间以方法上的时间为准,这里的现象是属性覆盖 timeout超时是在执行SQL时候检查, 是否超时!

3.2.1事务的回滚规则

1默认情况下,业务方法抛出运行时异常(RuntimeException),事务回滚.

2可以自定义回滚规则,通过属性rollbackFor和noRollBackFor来指定

3.2.2事务的隔离级别:

isolation = Isolation.READ_UNCOMMITTED 读未提交, 不可以避免脏读, 幻读, 可重复读, 并发性好

isolation = Isolation.READ_COMMITTED 读已提交, 建议使用, 不可以避免幻读, 可以避免重复读, 并发性能好

isolation = Isolation.REPEATABLE_READ 可以重复读, 不可以避免幻读, 一定并发性能

isolation = Isolation.SERIALIZABLE 序列化, 完全隔离, 不能并发, 性能不好

常用的是 READ_COMMITTED

小技巧

@Transacational注解作用在集成测试

该注解可以作用在测试方法/类上方,但是执行之后会自动回滚,避免测试之后对数据进行清理

/**

 * 测试事务作用在测试方法上方,执行结束,自动回滚
 */
@Test
@Transactional
public void deleteTest(){
    Student student = studentService.findStudent(3);
    logger.debug("找到 {}", student);
    studentService.deleteStudentById(3);
    student = studentService.findStudent(3);
    logger.debug("没有了 {}", student);
}

3.3分布式事务管理

        在微服务的项目中,业务逻辑层涉及远程调用,当前模块发生异常,无法操作远程服务器回滚

这时要想让远程调用也支持事务功能,就需要使用分布式事务组件Seata

Seata保证微服务远程调用业务的原子性

Seata将为用户提供了 AT、TCC、SAGA 和 XA 事务模式,为用户打造一站式的分布式解决方案。

上面结构是比较典型的远程调用结构

如果account操作数据库失败需要让order模块和storage模块撤销(回滚)操作

声明式事务不能完成这个操作

需要使用Seata来解决

Seata构成部分包含

事务协调器TC

事务管理器TM

资源管理器RM

AT模式运行过程

1.事务的发起方(TM)会向事务协调器(TC)申请一个全局事务id,并保存

2.Seata会管理事务中所有相关的参与方的数据源,将数据操作之前和之后的镜像都保存在undo_log表中,这个表是seata组件规定的表,没有它就不能实现效果,依靠它来实现提交(commit)或回滚(roll back)的操作

3.事务的发起方(TM)会连同全局id一起通过远程调用运行资源管理器(RM)中的方法

4.RM接收到全局id,去运行指定方法,并将运行结果的状态发送给TC

5.如果所有分支运行都正常,事务管理器(TM)会通过事务协调器通知所有模块执行数据库操作,真正影响数据库内容,反之如果有任何一个分支模块运行异常,都会通知TC,再由TC通知所有分支将数据库操作回滚,恢复成运行之前的样子。

4.Seata的启动

seata也是java开发的,启动方式和nacos很像

只是启动命令不同

在路径上输入cmd进入dos窗口

D:\tools\seata\seata-server-1.4.2\bin>seata-server.bat -h 127.0.0.1 -m file

输入后,最后出现8091端口的提示即可!

AT模式

AT模式的运行有一个非常明显的前提条件,这个条件不满足,就无法使用AT模式

这个条件就是事务分支都必须是操作关系型数据库(mysql\MariaDB\Oracle)

因为关系型数据库才支持提交和回滚,其它非关系型数据库都是直接影响数据(例如Redis)

所以如果我们在业务过程中有一个节点操作的是Redis或其它非关系型数据库时,就无法使用AT模式

除了AT模式之外还有TCC、SAGA 和 XA 事务模式

TCC模式

简单来说,TCC模式就是自己编写代码完成事务的提交和回滚

在TCC模式下,我们需要为参与事务的业务逻辑编写一组共3个方法

(prepare\commit\rollback)

prepare:准备

commit:提交

rollback:回滚

  • prepare方法是每个模块都会运行的方法
  • 当所有模块的prepare方法运行都正常时,运行commit
  • 当任意模块运行的prepare方法有异常时,运行rollback

这样的话所有提交或回滚代码都由自己编写

优点:虽然代码是自己写的,但是事务整体提交或回滚的机制仍然可用(仍然由TC来调度)

缺点:每个业务都要编写3个方法来对应,代码冗余,而且业务入侵量大

SAGA模式

SAGA模式的思想是对应每个业务逻辑层编写一个新的类,可以设置指定的业务逻辑层方法发生异常时,运行当新编写的类中的代码

这样编写代码不影响已经编写好的业务逻辑代码

一般用于修改已经编写完成的老代码

缺点是每个事务分支都要编写一个类来回滚业务,

会造成类的数量较多,开发量比较大

XA模式

支持XA协议的数据库分布式事务,使用比较少

5.配置使用Seata

<!--   Seata和SpringBoot整合依赖     -->
<dependency>
    <groupId>io.seata</groupId>
    <artifactId>seata-spring-boot-starter</artifactId>
</dependency>
<!--  Seata 完成分布式事务的两个相关依赖(Seata会自动使用其中的资源)  -->
<dependency>
    <groupId>com.github.pagehelper</groupId>
    <artifactId>pagehelper-spring-boot-starter</artifactId>
</dependency>
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>fastjson</artifactId>
</dependency>
seata:
  tx-service-group: csmall_group  # 定义分组名称,为了与其它项目区分
  service:
    vgroup-mapping:
      csmall_group: default       # csmall_group分组使用Seata的默认配置完成事务  
    grouplist: 
      default: localhost:8091     # 配置seata的地址和端口号(8091是默认端口号)

 在想要进行事务管理的方法上方加@GlobalTransactional

Global全局,Transactional事务
  一旦编写@GlobalTransactional标记这个方法
   就相当于设置了分布式事务的起点,当前模块就是分布式事务模型中的TM
   最终效果是由当前方法调用的所有远程服务中对数据库的操作要么都执行,要么都不执行 

 // Global全局,Transactional事务
    // 一旦编写@GlobalTransactional标记这个方法
    // 就相当于设置了分布式事务的起点,当前模块就是分布式事务模型中的TM
    // 最终效果是由当前方法调用的所有远程服务中对数据库的操作要么都执行,要么都不执行 
@GlobalTransactional

猜你喜欢

转载自blog.csdn.net/Lee_92/article/details/126517415