• Seata分布式事务


    1.Seata介绍

    Seata是由阿里中间件团队发起的开源项目 Fescar,后更名为Seata,它是一个是开源的分布式事务框架。

    传统2PC的问题在Seata中得到了解决,它通过对本地关系数据库的分支事务的协调来驱动完成全局事务。

    是工作在应用层的中间件。主要优点是性能较好,且不长时间占用连接资源,它以高效并且对业务0侵入的方式解决微服 务场景下面临的分布式事务问题,它目前提供AT模式(即2PC)及TCC模式的分布式事务解决方案。

    1.1. Seata的设计思想

    seata 采用的是大量运用在数据库软件的 Write Ahead Log 思想,即把事务的信息以事务日志的方式记录下来。这种处理方式,实际上是对传统两阶段提交的一种改进和优化。主要有几个关键点:

    1. 传统两阶段提交协议是阻塞协议,性能差

    2. 传统两阶段提交协议高可用性不好

    3. 传统两阶段提交协议的全局事务隔离机制不支持

    4. 根据八二原则,80% 的涉及到全局事务的业务是能正常完成并提交的。

    因此,seata 采取的做法是,一个事务分支的数据库操作执行完后,马上进行本地事务的提交,从而释放相关的数据库 资源。

     

    • 分支事务中数据的 本地锁 由本地事务管理,在分支事务 Phase1 结束时释放。·

    • 同时,随着本地事务结束,连接 也得以释放。·

    • 分支事务中数据的 全局锁 在事务协调器侧管理,在决议 Phase2 全局提交时,全局锁马上可以释放。只有在决议全 局回滚的情况下,全局锁 才被持有至分支的 Phase2 结束。

    1.2.本地事务执行流程

    在进行本地提交的前提是,seata 会解析 SQL,获取数据库表的元数据,根绝 SQL 类型,选择性地生成数据的前置镜像和后置镜像, 保存在 undolog 表中,并且要求与保存 undolog 与业务 SQL 在同一个本地事务内。

    这就保证了:

    1. 如果一个本地事务被提交,那么必定对应着相应的 undo_log

    2. 如果保存 undo_log 保存失败,那么业务 SQL 也会失败

     

    1.3.全局事务提交流程

    因为每个分支事务的本地事务都已经被提交,所以如果全局事务能够顺利进行到“提交“这一阶段,那么意味着所有事务分支的本地事 务都已经被提交了,数据的一致性已经得到了保证。

    这个时候全局事务的提交就变得十分轻量级,就是把 undo_log 对应的记录删掉即可,即使是当时删除失败了,也已经不会影响全局事 务的最终结果,这次删不了,那就待会再删,程序删不了,没事,顶多人工删。

     

    1.4.全局事务回滚流程

    如果全局事务的任何一个事务分支失败了,那么全局事务就进入“回滚“流程,回滚时依据先前保存好数据镜像,将原来的数据回放回去。

    如果全局回放成功,那么数据的一致性也就得到了保证,如果回放不成功,那么事务就进入异常。应对异常,可能需要重试,可能需要人工介入。

     

    2.Seata在dubbo中的使用

    2.1.新增mvn依赖

    在需要增加分布式事务的模块加上相关依赖

    1. io.seata

    2. seata-spring-boot-starter

    3. 1.1.0

    2.2.修改properties文件

    1. #服务名称

    2. dubbo.application.name=service

    3. #注册中心地址

    4. dubbo.registry.address=127.0.0.1:2181

    5. #注册中心类型

    6. dubbo.registry.protocol=zookeeper

    7. #版本号

    8. dubbo.application.version=3

    9. # Dubbo Protocol

    10. #协议名称

    11. dubbo.protocol.name=dubbo

    12. #服务暴露端口

    13. dubbo.protocol.port=20880

    14. seata.enabled=true

    15. seata.application-id=biz-service

    16. seata.tx-service-group=my_test_tx_group

    17. seata.client.rm.async-commit-buffer-limit=1000

    18. seata.client.rm.report-retry-count=5

    19. seata.client.rm.table-meta-check-enable=false

    20. seata.client.rm.report-success-enable=false

    21. seata.client.rm.lock.retry-interval=10

    22. seata.client.rm.lock.retry-times=30

    23. seata.client.rm.lock.retry-policy-branch-rollback-on-conflict=true

    24. seata.client.tm.commit-retry-count=5

    25. seata.client.tm.rollback-retry-count=5

    26. seata.client.undo.data-validation=true

    27. seata.client.undo.log-serialization=jackson

    28. seata.client.undo.log-table=undo_log

    29. seata.client.log.exceptionRate=100

    30. seata.service.vgroup-mapping.my_test_tx_group=default

    31. seata.service.grouplist.default=127.0.0.1:8091

    32. seata.transport.shutdown.wait=3

    33. seata.transport.thread-factory.boss-thread-prefix=NettyBoss

    34. seata.transport.thread-factory.worker-thread-prefix=NettyServerNIOWorker

    35. seata.transport.thread-factory.server-executor-thread-prefix=NettyServerBizHandler

    36. seata.transport.thread-factory.share-boss-worker=false

    37. seata.transport.thread-factory.client-selector-thread-prefix=NettyClientSelector

    38. seata.transport.thread-factory.client-selector-thread-size=1

    39. seata.transport.thread-factory.client-worker-thread-prefix=NettyClientWorkerThread

    40. seata.transport.thread-factory.worker-thread-size=default

    41. seata.transport.thread-factory.boss-thread-size=1

    42. seata.transport.type=TCP

    43. seata.transport.server=NIO

    44. seata.transport.heartbeat=true

    45. seata.transport.serialization=seata

    46. seata.transport.compressor=none

    47. seata.transport.enable-client-batch-send-request=true

    48. seata.config.type=file

    49. seata.registry.type=file

    2.3.新增配置类

    1. package cn.enjoy.mt.order.config;

    2. import com.alibaba.druid.pool.DruidDataSource;

    3. import org.apache.ibatis.session.SqlSessionFactory;

    4. import org.mybatis.spring.SqlSessionFactoryBean;

    5. import org.springframework.boot.context.properties.ConfigurationProperties;

    6. import org.springframework.context.annotation.Bean;

    7. import org.springframework.context.annotation.Configuration;

    8. import org.springframework.core.io.support.PathMatchingResourcePatternResolver;

    9. import javax.sql.DataSource;

    10. @Configuration

    11. public class SeataConfiguration {

    12. @Bean

    13. @ConfigurationProperties(prefix = "spring.datasource")

    14. public DataSource druidDataSource() {

    15. DruidDataSource druidDataSource = new DruidDataSource();

    16. return druidDataSource;

    17. }

    18. @Bean

    19. public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception {

    20. SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean();

    21. factoryBean.setDataSource(dataSource);

    22. factoryBean.setMapperLocations(new PathMatchingResourcePatternResolver()

    23. .getResources("classpath:/mapping/.xml"));

    24. return factoryBean.getObject();

    25. }

    26. }

    2.4.新增undo_log日志表

    1. CREATE TABLE undo_log (

    2. id bigint(20) NOT NULL AUTO_INCREMENT,

    3. branch_id bigint(20) NOT NULL,

    4. xid varchar(100) NOT NULL,

    5. context varchar(128) NOT NULL,

    6. rollback_info longblob NOT NULL,

    7. log_status int(11) NOT NULL,

    8. log_created datetime NOT NULL,

    9. log_modified datetime NOT NULL,

    10. ext varchar(100) DEFAULT NULL,

    11. PRIMARY KEY (id),

    12. UNIQUE KEY ux_undo_log (xid,branch_id)

    13. ) ENGINE=InnoDB DEFAULT CHARSET=utf8;

    2.5.SeataProperties

    1. package cn.enjoy.mt.order.config;

    2. import org.springframework.boot.context.properties.ConfigurationProperties;

    3. @ConfigurationProperties("spring.cloud.alibaba.seata")

    4. public class SeataProperties {

    5. private String txServiceGroup;

    6. public SeataProperties() {

    7. }

    8. public String getTxServiceGroup() {

    9. return this.txServiceGroup;

    10. }

    11. public void setTxServiceGroup(String txServiceGroup) {

    12. this.txServiceGroup = txServiceGroup;

    13. }

    14. }

    2.6.修改启动类

    1. package cn.enjoy.mt.order;

    2. import org.apache.dubbo.config.spring.context.annotation.EnableDubbo;

    3. import org.mybatis.spring.annotation.MapperScan;

    4. import org.springframework.boot.SpringApplication;

    5. import org.springframework.boot.autoconfigure.SpringBootApplication;

    6. import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;

    7. import org.springframework.cache.annotation.EnableCaching;

    8. import org.springframework.context.annotation.PropertySource;

    9. @SpringBootApplication(exclude = DataSourceAutoConfiguration.class)

    10. @EnableDubbo

    11. @PropertySource("classpath:mt_db.properties")

    12. @MapperScan("cn.enjoy.mt.dao")

    13. @EnableCaching

    14. public class OrderServiceApp {

    15. public static void main(String[] args) {

    16. SpringApplication.run(OrderServiceApp.class,args);

    17. }

    18. }

    2.7.增加 @GlobalTransactional注解

    2.7.1.产品服务

    1. @GlobalTransactional

    2. public void deleteById(Integer id) {

    3. orderService.deleteByProductId(id);

    4. int i = 10/0;

    5. productInfoMapper.deleteByPrimaryKey(id);

    6. }

    2.7.2.订单服务

    1. @Override

    2. @GlobalTransactional

    3. public void deleteByProductId(int id) {

    4. orderInfoMapper.deleteByProductId(id);

    5. }

  • 相关阅读:
    【09】Spring源码-分析篇-DI源码分析
    IDM(Internet Download Manager)2024免激活绿色版下载
    java动态合并表格
    Perl 语言入门教程
    (附源码)php二手服装网站 毕业设计 201711
    Redis Sentinel工作原理
    大语言模型(LLM)综述(三):大语言模型预训练的进展
    命令的历史管理
    企业落地数字化转型,战略规划应该放在首要位置
    正则表达式匹配html中的图片地址
  • 原文地址:https://blog.csdn.net/zhaohuodian/article/details/126386758