Spring分布式事务实现
分布式事务的实现方法
分布式事务的实现方法
分布式事务的实现方法有多种,以下是其中几种常见的方案:
1. 两阶段提交(XA 方案):事务管理器先询问各个数据库是否准备好了,每个要操作的数据库都回复事务管理器ok,那么就正式提交事务。
2. TCC方案:TCC的全称是:Try、Confirm、Cancel。
Try阶段是对各个服务的资源做检测以及对资源进行锁定或者预留;Confirm阶段是在各个服务中执行实际的操作;Cancel阶段是如果任何一个服务的业务方法执行出错,那么就需要进行补偿,即执行已经执行成功的业务逻辑的回滚操作。
一般来说,支付、交易等需要严格保证资金正确性的场景会使用TCC方案。
3. 可靠消息最终一致性方案:通过消息队列将分布式事务中的操作进行异步解耦,从而实现最终的一致性。
这种方式能够处理大量并发操作,但是可能会存在数据不一致的风险。
4. 最大努力通知方案:通过最大努力的方式将通知发送给其他服务,以实现分布式事务的一致性。
这种方式简单易行,但是可能会因为网络问题或者服务不可用等原因导致通知失败。
5. SAGA方案:SAGA是一种基于事务的分布式事务处理模型,它将一个分布式事务视为一系列本地事务的组合。
每个本地事务在一个单独的节点上执行,并且通过消息传递进行通信。
SAGA能够保证全局事务的最终一致性,同时具有较好的容错性和可恢复性。
以上是分布式事务的几种常见实现方案,每种方案都有其优缺点,需要根据具体的业务场景和需求来选择适合的方案。
SpringCloud分布式事务的解决方案
SpringCloud分布式事务的解决⽅案常见的分布式解决⽅案1、两阶段提交协议(2PC) 解决分布式系统的数据⼀致性问题出现了两阶段提交协议(2 Phase Commitment Protocol),两阶段提交由协调者和参与者组成,共经过两个阶段和三个操作,部分关系数据库如Oracle、MySQL⽀持两阶段提交协议。
说到2pc就不得不聊聊数据库分布式事务中的XA transactions在XA协议中分为两阶段:第⼀阶段:事务管理器要求每个涉及到事务的数据库预提交(precommit)此操作,并反映是否可以提交.第⼆阶段:事务协调器要求每个数据库提交数据,或者回滚数据。
举⼀个例⼦:1、应⽤程序通过事务协调器向两个库发起prepare,两个数据库收到消息分别执⾏本地事务(记录⽇志), 但不提交,如果执⾏成功则回复yes,否则回复no。
2、事务协调器收到回复,只要有⼀⽅回复no则分别向参与者发起回滚事务,参与者开始回滚事务。
3、事务协调器收到回复,全部回复yes,此时向参与者发起提交事务。
如果参与者有⼀⽅提交事务失败则由事务协调器发起回滚事务。
优点: 尽量保证了数据的强⼀致,实现成本较低,在各⼤主流数据库都有⾃⼰实现,对于MySQL是从5.5开始⽀持。
缺点:单点问题:事务管理器在整个流程中扮演的⾓⾊很关键,如果其宕机,⽐如在第⼀阶段已经完成, 在第⼆阶段正准备提交的时候事务管理器宕机,资源管理器就会⼀直阻塞,导致数据库⽆法使⽤。
同步阻塞:在准备就绪之后,资源管理器中的资源⼀直处于阻塞,直到提交完成,释放资源。
数据不⼀致:两阶段提交协议虽然为分布式数据强⼀致性所设计,但仍然存在数据不⼀致性的可能,⽐如在第⼆阶段中,假设协调者发出了事务commit的通知,但是因为⽹络问题该通知仅被⼀部分参与者所收到并执⾏了commit操作,其余的参与者则因为没有收到通知⼀直处于阻塞状态,这时候就产⽣了数据的不⼀致性。
Java中的分布式事务和分布式锁应用
Java中的分布式事务和分布式锁应用分布式系统是指在多台计算机中协同工作的系统,它们可以通过网络进行通信和协作,以实现特定的功能。
由于分布式系统的复杂性和需要处理的数据量庞大,分布式事务和分布式锁成为了开发者们关注的热点问题。
在本文中,我们将深入探讨Java中的分布式事务和分布式锁的应用,包括其基本概念、原理、使用场景以及常见的实现方式。
一、分布式事务的概念与实现1.分布式事务的概念在分布式系统中,由于数据存储在不同的节点上,不同的操作可能需要跨多个节点进行协同操作。
分布式事务就是对这些分布在不同节点上的操作进行统一的管理,保证所有操作要么全部成功,要么全部失败,从而确保系统的一致性和可靠性。
2. ACID原则在传统的单机事务中,事务必须满足ACID原则,即原子性(Atomicity)、一致性(Consistency)、隔离性(Isolation)和持久性(Durability)。
而在分布式系统中,要求事务的ACID原则不仅适用于单个节点,还需要保证在多个节点上的事务也满足ACID原则。
3.分布式事务的实现方式Java中常见的分布式事务解决方案有两种:XA事务和柔性事务。
(1) XA事务是分布式事务的一种标准化解决方案,它允许多个资源(如数据库)参与到一个事务中,通过两阶段提交协议来保证事务的一致性。
(2)柔性事务是一种更加灵活和轻量级的分布式事务解决方案,它通常采用了类似“最终一致性”、“补偿事务”等策略来保证分布式系统中的数据一致性。
二、分布式事务的应用场景由于分布式系统中的数据分片和分布在不同的节点上,导致了分布式事务在应用场景中的困难与复杂度。
以下是几个常见的分布式事务应用场景:1.跨服务的事务处理:当一个业务操作需要跨多个服务进行协同操作时,需要使用分布式事务来协调各个服务的操作。
2.跨数据库的事务管理:当业务系统中使用多个数据库进行数据存储时,需要使用分布式事务来保证多个数据库操作的一致性。
功能测试中的分布式事务验证
功能测试中的分布式事务验证分布式系统是现代软件开发中常见的架构模式,它将系统的各个组件分散在不同的物理或逻辑节点上,通过网络进行通信和协调。
在分布式系统中,事务管理一直是一个挑战,特别是对于涉及多个节点的分布式事务。
为了保证分布式事务的一致性和完整性,功能测试中的分布式事务验证变得至关重要。
一、分布式事务概述分布式事务是指涉及多个节点的事务操作,这些节点可以是不同的进程、不同的服务或不同的数据库。
在分布式系统中,各个节点之间的通信存在网络延迟、中断等问题,因此需要一种机制来确保在事务执行期间的一致性和隔离性。
分布式事务的核心目标是保证所有节点的数据在执行事务期间保持一致性,并在事务提交或回滚后得到正确的结果。
二、功能测试中的分布式事务验证重要性在开发和测试分布式系统时,保证系统在各种异常情况下依然能够保持一致性和完整性是至关重要的。
功能测试中的分布式事务验证可以帮助开发人员和测试人员发现潜在的问题,并及时修复,从而提高系统的可靠性和稳定性。
通过对分布式事务进行验证,可以确保系统的各个组件在联合工作时能够正确处理事务边界、失败恢复、数据一致性等关键问题。
三、功能测试中的分布式事务验证方法1. 设计合理的测试用例:根据系统的具体场景和需求,设计一组全面、完整的测试用例来验证分布式事务的各个方面。
测试用例应该覆盖不同的分布式事务场景,包括正常情况下的事务执行、异常情况下的事务回滚、网络故障处理等。
2. 模拟网络延迟和中断:通过模拟网络延迟和中断等异常情况,验证系统在不稳定的网络环境下的分布式事务处理能力。
例如,可以使用工具模拟网络故障或者手动断开节点之间的通信,观察系统的行为和响应。
3. 监控和记录事务执行过程:使用监控工具,实时监测分布式事务的执行情况,包括各个节点的状态、事务日志、数据传输等。
通过记录事务执行过程中的关键信息,便于分析和排查问题。
4. 数据一致性验证:在分布式系统中,数据一致性是一个核心问题。
SpringCloudAlibaba使用Seata处理分布式事务的技巧
SpringCloudAlibaba使⽤Seata处理分布式事务的技巧Seata简介在传统的单体项⽬中,我们使⽤@Transactional注解就能实现基本的ACID事务了。
但是前提是:1)数据库⽀持事务(如:MySQL的innoDB引擎)2)所有业务都在同⼀个数据库中执⾏随着微服务架构的引⼊,需要对数据库进⾏分库分表,每个服务拥有⾃⼰的数据库,这样传统的事务就不起作⽤了,那么我们如何保证多个服务中数据的⼀致性呢?这样就出现了分布式事务,⽽Seata就是为微服务架构⽽⽣的⼀种⾼性能、易于使⽤的分布式事务解决⽅案。
Seata 中有三个基础组件:1. Transaction Coordinator(TC协调者):维护全局和分⽀事务的状态,驱动全局提交或回滚。
2. Transaction Manager(TM事务管理):定义全局事务的范围,开启、提交或回滚⼀个全局事务。
3. Resource Manager(RM资源管理):管理分⽀事务资源,与 TC 通讯并报告分⽀事务状态,管理本地事务的提交与回滚。
可以这么说⼀个分布式事务就是全局事务GlobalTransaction,⽽全局事务是由⼀个个的分⽀事务组成的,每个分⽀事务就是⼀个本地事务。
Seata的⽣命周期1. TM 要求 TC ⽣成⼀个全局事务,并由 TC ⽣成⼀个全局事务XID 返回。
2. XID 通过微服务调⽤链传播。
3. RM 向 TC 注册本地事务,将其注册到 ID 为 XID 的全局事务中。
4. TM 要求 TC 提交或回滚XID 对应的全局事务。
5. TC 驱动 XID 对应的全局事务对应的所有的分⽀事务提交或回滚。
Seata安装和配置startup -m standalone安装和配置Seatafile.conf主要是数据库的配置,配置如下registry.conf 是注册中⼼的配置另外conf⽬录中还需要⼀个脚本⽂件:nacos-config.sh ⽤于对nacos进⾏初始化配置在seata1.4.0中是没有的,需要⾃⾏创建,内容如下:#!/usr/bin/env bash# Copyright 1999-2019 Seata.io Group.## Licensed under the Apache License, Version 2.0 (the "License");# you may not use this file except in compliance with the License.# You may obtain a copy of the License at、## /licenses/LICENSE-2.0## Unless required by applicable law or agreed to in writing, software# distributed under the License is distributed on an "AS IS" BASIS,# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.# See the License for the specific language governing permissions and# limitations under the License.while getopts ":h:p:g:t:u:w:" optdocase $opt inh)host=$OPTARG;;p)port=$OPTARG;;g)group=$OPTARG;;t)tenant=$OPTARG;;u)username=$OPTARG;;w)password=$OPTARG;;)echo " USAGE OPTION: $0 [-h host] [-p port] [-g group] [-t tenant] [-u username] [-w password] " exit 1;;esacdoneurlencode() {for ((i=0; i < ${#1}; i++))dochar="${1:$i:1}"case $char in[a-zA-Z0-9.~_-]) printf $char ;;*) printf '%%%02X' "'$char" ;;esacdone}if [[ -z ${host} ]]; thenhost=localhostfiif [[ -z ${port} ]]; thenport=8848fiif [[ -z ${group} ]]; thengroup="SEATA_GROUP"fiif [[ -z ${tenant} ]]; thentenant=""fiif [[ -z ${username} ]]; thenusername=""fiif [[ -z ${password} ]]; thenpassword=""finacosAddr=$host:$portcontentType="content-type:application/json;charset=UTF-8"echo "set nacosAddr=$nacosAddr"echo "set group=$group"failCount=0tempLog=$(mktemp -u)function addConfig() {curl -X POST -H "${contentType}" "http://$nacosAddr/nacos/v1/cs/configs?dataId=$(urlencode $1)&group=$group&content=$(urlencode $2)&tenant=$tenant&username=$username&password=$password" >"${tempLog}" 2>/dev/null if [[ -z $(cat "${tempLog}") ]]; thenecho " Please check the cluster status. "exit 1fiif [[ $(cat "${tempLog}") =~ "true" ]]; thenecho "Set $1=$2 successfully "elseecho "Set $1=$2 failure "(( failCount++ ))fi}count=0for line in $(cat $(dirname "$PWD")/config.txt | sed s/[[:space:]]//g); do(( count++ ))key=${line%%=*}value=${line#*=}addConfig "${key}" "${value}"doneecho "========================================================================="echo " Complete initialization parameters, total-count:$count , failure-count:$failCount "echo "========================================================================="if [[ ${failCount} -eq 0 ]]; thenecho " Init nacos config finished, please start seata-server. "elseecho " init nacos config fail. "fi在seata的根⽬录,与conf同级的⽬录下,还需要config.txt 配置⽂件,默认也是没有的只需要对mysql的配置进⾏修改完整⽂件:transport.type=TCPtransport.server=NIOtransport.heartbeat=truetransport.enableClientBatchSendRequest=truetransport.threadFactory.bossThreadPrefix=NettyBosstransport.threadFactory.workerThreadPrefix=NettyServerNIOWorkertransport.threadFactory.serverExecutorThreadPrefix=NettyServerBizHandlertransport.threadFactory.shareBossWorker=falsetransport.threadFactory.clientSelectorThreadPrefix=NettyClientSelectortransport.threadFactory.clientSelectorThreadSize=1transport.threadFactory.clientWorkerThreadPrefix=NettyClientWorkerThreadtransport.threadFactory.bossThreadSize=1transport.threadFactory.workerThreadSize=defaulttransport.shutdown.wait=3service.vgroupMapping.my_test_tx_group=defaultservice.default.grouplist=127.0.0.1:8091service.enableDegrade=falseservice.disableGlobalTransaction=falseclient.rm.asyncCommitBufferLimit=10000client.rm.lock.retryInterval=10client.rm.lock.retryTimes=30client.rm.lock.retryPolicyBranchRollbackOnConflict=trueclient.rm.reportRetryCount=5client.rm.tableMetaCheckEnable=falseclient.rm.tableMetaCheckerInterval=60000client.rm.sqlParserType=druidclient.rm.reportSuccessEnable=falseclient.rm.sagaBranchRegisterEnable=falseclient.rm.tccActionInterceptorOrder=-2147482648mitRetryCount=5client.tm.rollbackRetryCount=5client.tm.defaultGlobalTransactionTimeout=60000client.tm.degradeCheck=falseclient.tm.degradeCheckAllowTimes=10client.tm.degradeCheckPeriod=2000client.tm.interceptorOrder=-2147482648store.mode=filestore.lock.mode=filestore.session.mode=filestore.publicKey=xxstore.file.dir=file_store/datastore.file.maxBranchSessionSize=16384store.file.maxGlobalSessionSize=512store.file.fileWriteBufferCacheSize=16384store.file.flushDiskMode=asyncstore.file.sessionReloadReadSize=100store.db.datasource=druidstore.db.dbType=mysqlstore.db.driverClassName=com.mysql.jdbc.Driverstore.db.url=jdbc:mysql://127.0.0.1:3306/seata?useUnicode=true&rewriteBatchedStatements=true er=rootstore.db.password=123456store.db.minConn=5store.db.maxConn=30store.db.globalTable=global_tablestore.db.branchTable=branch_tablestore.db.queryLimit=100store.db.lockTable=lock_tablestore.db.maxWait=5000store.redis.mode=singlestore.redis.single.host=127.0.0.1store.redis.single.port=6379store.redis.sentinel.masterName=xxstore.redis.sentinel.sentinelHosts=xxstore.redis.maxConn=10store.redis.minConn=1store.redis.maxTotal=100store.redis.database=0store.redis.password=xxstore.redis.queryLimit=100mittingRetryPeriod=1000server.recovery.asynCommittingRetryPeriod=1000server.recovery.rollbackingRetryPeriod=1000server.recovery.timeoutRetryPeriod=1000server.maxCommitRetryTimeout=-1server.maxRollbackRetryTimeout=-1server.rollbackRetryTimeoutUnlockEnable=falseserver.distributedLockExpireTime=10000client.undo.dataValidation=trueclient.undo.logSerialization=jacksonclient.undo.onlyCareUpdateColumns=trueserver.undo.logSaveDays=7server.undo.logDeletePeriod=86400000client.undo.logTable=undo_logpress.enable=truepress.type=zippress.threshold=64klog.exceptionRate=100transport.serialization=seatapressor=nonemetrics.enabled=falsemetrics.registryType=compactmetrics.exporterList=prometheusmetrics.exporterPrometheusPort=9898在conf⽬录中,使⽤Git Bash进⼊命令⾏,输⼊sh nacos-config.sh 127.0.0.1这是对Seata进⾏初始化配置,上图表⽰所有配置都成功设置了在nacos中可以看到出现了seata相关的配置接下来在seata数据库中,新建三个表drop table if exists `global_table`;create table `global_table` (`xid` varchar(128) not null,`transaction_id` bigint,`status` tinyint not null,`application_id` varchar(32),`transaction_service_group` varchar(32),`transaction_name` varchar(128),`timeout` int,`begin_time` bigint,`application_data` varchar(2000),`gmt_create` datetime,`gmt_modified` datetime,primary key (`xid`),key `idx_gmt_modified_status` (`gmt_modified`, `status`),key `idx_transaction_id` (`transaction_id`));drop table if exists `branch_table`;create table `branch_table` (`branch_id` bigint not null,`xid` varchar(128) not null,`transaction_id` bigint ,`resource_group_id` varchar(32),`resource_id` varchar(256) ,`lock_key` varchar(128) ,`branch_type` varchar(8) ,`status` tinyint,`client_id` varchar(64),`application_data` varchar(2000),`gmt_create` datetime,`gmt_modified` datetime,primary key (`branch_id`),key `idx_xid` (`xid`));drop table if exists `lock_table`;create table `lock_table` (`row_key` varchar(128) not null,`xid` varchar(96),`transaction_id` long ,`branch_id` long,`resource_id` varchar(256) ,`table_name` varchar(32) ,`pk` varchar(36) ,`gmt_create` datetime ,`gmt_modified` datetime,primary key(`row_key`));在项⽬相关的数据库中,新建表undo_log ⽤于记录撤销⽇志CREATE TABLE `undo_log` (`id` bigint(20) NOT NULL AUTO_INCREMENT,`branch_id` bigint(20) NOT NULL,`xid` varchar(100) NOT NULL,`context` varchar(128) NOT NULL,`rollback_info` longblob NOT NULL,`log_status` int(11) NOT NULL,`log_created` datetime NOT NULL,`log_modified` datetime NOT NULL,`ext` varchar(100) DEFAULT NULL,PRIMARY KEY (`id`),UNIQUE KEY `ux_undo_log` (`xid`,`branch_id`)) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;最后在bin⽬录中,启动命令⾏,执⾏seata-server.bat 启动Seata服务项⽬应⽤SeataSpringCloud项⽬中有两个服务:订单服务和库存服务,基本业务是:购买商品插⼊订单减少库存订单详情表DROP TABLE IF EXISTS `tb_order_detail`;CREATE TABLE `tb_order_detail` (`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '订单详情id ',`order_id` bigint(20) NOT NULL COMMENT '订单id',`sku_id` bigint(20) NOT NULL COMMENT 'sku商品id',`num` int(11) NOT NULL COMMENT '购买数量',`title` varchar(256) NOT NULL COMMENT '商品标题',`own_spec` varchar(1024) DEFAULT '' COMMENT '商品动态属性键值集',`price` bigint(20) NOT NULL COMMENT '价格,单位:分',`image` varchar(128) DEFAULT '' COMMENT '商品图⽚',PRIMARY KEY (`id`),KEY `key_order_id` (`order_id`) USING BTREE) ENGINE=MyISAM AUTO_INCREMENT=131 DEFAULT CHARSET=utf8 COMMENT='订单详情表';库存表DROP TABLE IF EXISTS `tb_stock`;CREATE TABLE `tb_stock` (`sku_id` bigint(20) NOT NULL COMMENT '库存对应的商品sku id',`seckill_stock` int(9) DEFAULT '0' COMMENT '可秒杀库存',`seckill_total` int(9) DEFAULT '0' COMMENT '秒杀总数量',`stock` int(9) NOT NULL COMMENT '库存数量',PRIMARY KEY (`sku_id`)) ENGINE=MyISAM DEFAULT CHARSET=utf8 COMMENT='库存表,代表库存,秒杀库存等信息';⽗项⽬定义了springboot、springcloud、springcloud-alibaba的版本<parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.3.10.RELEASE</version><relativePath/> <!-- lookup parent from repository --></parent><dependencyManagement><dependencies><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-alibaba-dependencies</artifactId><version>0.9.0.RELEASE</version><type>pom</type><scope>import</scope></dependency><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-alibaba-dependencies</artifactId><version>2.2.1.RELEASE</version><type>pom</type><scope>import</scope></dependency><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-dependencies</artifactId><version>Hoxton.SR8</version><type>pom</type><scope>import</scope></dependency></dependencies></dependencyManagement>⼦项⽬的依赖定义了nacos和seata客户端<dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><scope>runtime</scope></dependency><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>3.3.2</version></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId></dependency><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-seata</artifactId><exclusions><exclusion><groupId>io.seata</groupId><artifactId>seata-spring-boot-starter</artifactId></exclusion></exclusions></dependency><dependency><groupId>io.seata</groupId><artifactId>seata-spring-boot-starter</artifactId><version>1.2.0</version></dependency>⼦项⽬配置⽂件完整配置server:port: 8001spring:application:name: stock-servicecloud:nacos:discovery:server-addr: localhost:8848alibaba:seata:enabled: trueenable-auto-data-source-proxy: truetx-service-group: my_test_tx_groupregistry:type: nacosnacos:application: seata-serverserver-addr: 127.0.0.1:8848username: nacospassword: nacosconfig:type: nacosnacos:server-addr: 127.0.0.1:8848group: SEATA_GROUPusername: nacospassword: nacosservice:vgroup-mapping:my_test_tx_group: defaultdisable-global-transaction: falseclient:rm:report-success-enable: falsedatasource:driver-class-name: com.mysql.cj.jdbc.Driverurl: jdbc:mysql://localhost:3306/eshop?serverTimezone=UTC&useUnicode=true&useSSL=false&characterEncoding=utf8 username: rootpassword: 123456库存服务定义了减库存的⽅法@RestControllerpublic class StockController {@Autowiredprivate IStockService stockService;@PutMapping("/stock")public ResponseEntity<Stock> reduceSkuStock(@RequestParam("skuId")Long skuId,@RequestParam("number")Integer number){Stock stock = stockService.getById(skuId);if(stock.getStock() < number){throw new RuntimeException("库存不⾜,SkuId:" + skuId);}stock.setStock(stock.getStock() - number);stockService.updateById(stock);return ResponseEntity.ok(stock);}}订单服务在插⼊订单后,使⽤Feign调⽤了减库存的服务@Servicepublic class OrderDetailServiceImpl extends ServiceImpl<OrderDetailMapper, OrderDetail> implements IOrderDetailService {//库存服务Feign@Autowiredprivate StockFeignClient stockFeignClient;// @Transactional@GlobalTransactional(rollbackFor = {Exception.class})@Overridepublic void makeOrder(OrderDetail orderDetail) {this.save(orderDetail); //保存订单int x = 11 / 0; //抛出异常//减库存stockFeignClient.reduceSkuStock(orderDetail.getSkuId(),orderDetail.getNum());}}插订单和减库存属于两个服务,传统的@Transactional已经不能保证它们的原⼦性了这⾥使⽤了Seata提供的@GlobalTransactional全局事务注解,出现任何异常后都能实现业务回滚。
Spring事务配置的五种方式
Spring事务原理统观spring事务,围绕着两个核心PlatformTransactionManager和TransactionStatusspring提供了几个关于事务处理的类:TransactionDefinition //事务属性定义TranscationStatus //代表了当前的事务,可以提交,回滚。
PlatformTransactionManager这个是spring提供的用于管理事务的基础接口,其下有一个实现的抽象类AbstractPlatformTransactionManager,我们使用的事务管理类例如DataSourceTransactionManager等都是这个类的子类。
一般事务定义步骤:TransactionDefinition td = new TransactionDefinition();TransactionStatus ts = transactionManager.getTransaction(td);try{ //do sthmit(ts);}catch(Exception e){transactionManager.rollback(ts);}spring提供的事务管理可以分为两类:编程式的和声明式的。
编程式的,比较灵活,但是代码量大,存在重复的代码比较多;声明式的比编程式的更灵活。
编程式主要使用transactionTemplate。
省略了部分的提交,回滚,一系列的事务对象定义,需注入事务管理对象.void add(){transactionTemplate.execute( new TransactionCallback(){pulic Object doInTransaction(TransactionStatus ts){ //do sth}}}声明式:使用TransactionProxyFactoryBean:<bean id="userManager" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean"><property name="transactionManager"><ref bean="transactionManager"/></property><property name="target"><ref local="userManagerTarget"/></property><property name="transactionAttributes"><props><prop key="insert*">PROPAGATION_REQUIRED</prop><prop key="update*">PROPAGATION_REQUIRED</prop><prop key="*">PROPAGATION_REQUIRED,readOnly</prop></props></property></bean>围绕Poxy的动态代理能够自动的提交和回滚事务org.springframework.transaction.interceptor.TransactionProxyFactoryBeanPROPAGATION_REQUIRED--支持当前事务,如果当前没有事务,就新建一个事务。
spring 事务 实现原理
spring 事务实现原理Spring事务的实现原理主要依赖于数据库或者其他存储系统的事务功能。
1. 数据库事务支持:Spring事务的实现依赖于数据库的事务功能。
通常情况下,数据库支持ACID(原子性、一致性、隔离性和持久性)事务特性,可以通过SQL的BEGIN、COMMIT 和ROLLBACK等命令来控制事务的开始、提交和回滚操作。
2. 事务管理器:Spring框架提供了事务管理器(TransactionManager)接口,用于管理事务的开始、提交和回滚等操作。
事务管理器可以根据配置信息选择不同的实现,如使用JDBC事务管理器(DataSourceTransactionManager)或者JTA事务管理器(JtaTransactionManager)等。
3. 编程式事务:Spring框架提供了编程式事务管理的支持,通过编写代码显式地控制事务的边界。
开发者可以在代码中使用事务管理器的API来手动管理事务,包括事务的开始、提交和回滚等操作。
这种方式灵活性较高,但也需要开发者手动处理事务的细节。
4. 声明式事务:Spring框架还提供了声明式事务管理的支持,通过使用注解或者XML配置来定义事务的属性和边界。
开发者可以使用@Transactional注解或者事务配置元素来标记方法或者类,指示该方法或者类在执行时需要开启事务。
Spring会在方法调用前后自动地管理事务的开始、提交和回滚等操作。
5. 事务传播行为:Spring事务还支持事务传播行为的定义,即一个方法调用另一个带有事务的方法时事务该如何传播。
例如,当前方法可能会暂停事务、加入到现有的事务中或者创建一个新的事务。
Spring提供了多种事务传播行为的选项,如REQUIRED、REQUIRES_NEW、NESTED等,可以根据需要进行配置。
总的来说,Spring事务的实现原理是通过与数据库或其他存储系统的事务功能结合,通过事务管理器来管理事务的开始、提交和回滚等操作。
spring事务原理
spring事务原理数据库系统内,事务指一系列连续的操作,这系列操作被看作一个整体,要么完全执行,要么完全不执行,不会出现执行部分的情况,这是数据库系统的基本特征之一。
在传统数据库系统中,事务的管理是由数据库系统自身提供的一种功能,然而随着数据库系统的复杂性的增加,数据库中的事务管理越来越复杂,对数据库操作有更多的要求,这样就催生了应用层事务管理技术,而当前最流行的事务管理技术是Spring事务。
Spring事务是一种基于AOP(面向切面编程)的分布式事务管理技术,它能够帮助系统更好的控制事务的处理过程,从而使系统内的数据更加有效率的共享,降低数据库事务的管理复杂度,提高数据库系统的可用性及性能。
Spring事务原理包括几个要素:事务模型、分布式事务处理框架、事务实现机制以及事务管理工具等。
一、事务模型Spring事务原理的核心是事务模型,即它把事务分为两种:提交成功事务和失败事务,在Spring提供的事务模型中,每个事务都只有两种结果,要么提交成功,要么提交失败,而不存在半提交的状态。
在Spring的事务模型中,事务的分类还要求事务的原子性,它要求一旦提交事务,事务就不会再次改变,或者改变的程度会很小。
原子性还表明事务的执行要么完全成功,要么完全失败,不会出现半成功半失败的情况。
二、分布式事务处理框架Spring提供了基于AOP技术的分布式事务处理框架,这种分布式事务处理框架能够有效地支持不同数据库之间的事务处理,它包括三个部分:事务管理器(TransactionManager)、事务拦截器(TransactionInterceptor)和事务事件监听器(TransactionListener)。
事务管理器是Spring对分布式事务的抽象,它可以处理不同类型的事务,它的实现通常会涉及到一些事务拦截器。
事务拦截器是Spring提供的一种安全机制,它能够在事务处理过程中,根据配置的规则,来拦截事务的执行,以便能够在事务处理过程中发现任何可能存在的问题,并对其进行调整,使得事务能够顺利的提交。
解析分布式事务的四种解决方案
解析分布式事务的四种解决方案分布式事务指事务的操作位于不同的节点上,需要保证事务的 AICD 特性。
例如在下单场景下,库存和订单如果不在同一个节点上,就涉及分布式事务。
在分布式系统中,要实现分布式事务,无外乎那几种解决方案。
一、两阶段提交(2PC)两阶段提交(Two-phase Commit,2PC),通过引入协调者(Coordinator)来协调参与者的行为,最终决定这些参与者是否要真正执行事务。
1、运行过程①准备阶段:协调者询问参与者事务是否执行成功,参与者发回事务执行结果。
②提交阶段:如果事务在每个参与者上都执行成功,事务协调者发送通知让参与者提交事务;否则,协调者发送通知让参与者回滚事务。
需要注意的是,在准备阶段,参与者执行了事务,但是还未提交。
只有在提交阶段接收到协调者发来的通知后,才进行提交或者回滚。
2、存在的问题①同步阻塞:所有事务参与者在等待其它参与者响应的时候都处于同步阻塞状态,无法进行其它操作。
②单点问题:协调者在 2PC 中起到非常大的作用,发生故障将会造成很大影响。
特别是在阶段二发生故障,所有参与者会一直等待状态,无法完成其它操作。
③数据不一致:在阶段二,如果协调者只发送了部分 Commit 消息,此时网络发生异常,那么只有部分参与者接收到 Commit 消息,也就是说只有部分参与者提交了事务,使得系统数据不一致。
④太过保守:任意一个节点失败就会导致整个事务失败,没有完善的容错机制。
二、补偿事务(TCC)TCC 其实就是采用的补偿机制,其核心思想是:针对每个操作,都要注册一个与其对应的确认和补偿(撤销)操作。
它分为三个阶段:①Try 阶段主要是对业务系统做检测及资源预留。
②Confirm 阶段主要是对业务系统做确认提交,Try阶段执行成功并开始执行Confirm阶段时,默认 Confirm阶段是不会出错的。
即:只要Try成功,Confirm一定成功。
③Cancel 阶段主要是在业务执行错误,需要回滚的状态下执行的业务取消,预留资源释放。
分布式事务测试方法
分布式事务测试方法分布式事务是指分布式系统中多个操作需要保持一致性的情况下所采用的一种协调机制。
由于分布式环境的复杂性和不可预测性,分布式事务的正确性和可靠性是必须要保障的。
在开发分布式系统时,必须进行全面的测试以验证系统的正确性和可靠性。
本文将介绍分布式事务测试的方法。
1. 构建测试用例在测试分布式事务时,需要构建全面的测试用例,包括正常情况下的操作,异常情况下的操作以及边界情况下的操作。
测试用例应该覆盖所有的操作场景,包括多节点并发操作、单节点操作、网络异常操作、数据库异常操作等。
2. 模拟分布式环境在测试时需要模拟分布式环境,以验证在真实环境下的正确性和可靠性。
可以使用容器化技术来模拟多个节点和数据库,可以使用网络模拟工具来模拟不同的网络情况,也可以使用负载测试工具来模拟并发操作。
3. 验证系统的一致性在测试分布式事务时,需要验证系统的一致性是否得到了保障。
可以通过比较不同节点上的数据是否一致来验证系统的一致性。
如果系统的一致性得到了保障,那么测试就可以通过。
4. 验证系统的可靠性在测试分布式事务时,需要验证系统的可靠性是否得到了保障。
可以通过模拟网络异常或数据库异常等情况来验证系统的可靠性。
如果系统在异常情况下能够保持正常的运行,那么测试就可以通过。
5. 测试结果的分析和总结在测试分布式事务时,需要对测试结果进行分析和总结。
需要找出测试中出现的问题和不足,并提出相应的优化和改进措施。
同时,需要总结出测试结果,以供参考和借鉴。
总之,测试分布式事务是非常重要的,需要进行全面的测试以保证系统的正确性和可靠性。
通过构建测试用例、模拟分布式环境、验证系统的一致性和可靠性以及对测试结果进行分析和总结,可以有效地测试分布式事务。
详解Java分布式事务的6种解决方案
详解Java分布式事务的6种解决⽅案介绍在分布式系统、微服务架构⼤⾏其道的今天,服务间互相调⽤出现失败已经成为常态。
如何处理异常,如何保证数据⼀致性,成为微服务设计过程中,绕不开的⼀个难题。
在不同的业务场景下,解决⽅案会有所差异,常见的⽅式有:1. 阻塞式重试;2. 2PC、3PC 传统事务;3. 使⽤队列,后台异步处理;4. TCC 补偿事务;5. 本地消息表(异步确保);6. MQ 事务。
本⽂侧重于其他⼏项,关于 2PC、3PC 传统事务,⽹上资料已经⾮常多了,这⾥不多做重复。
阻塞式重试在微服务架构中,阻塞式重试是⽐较常见的⼀种⽅式。
伪代码⽰例:m := db.Insert(sql)err := request(B-Service,m)func request(url string,body interface{}){for i:=0; i<3; i ++ {result, err = request.POST(url,body)if err == nil {break}else {log.Print()}}}如上,当请求 B 服务的 API 失败后,发起最多三次重试。
如果三次还是失败,就打印⽇志,继续执⾏下或向上层抛出错误。
这种⽅式会带来以下问题1. 调⽤ B 服务成功,但由于⽹络超时原因,当前服务认为其失败了,继续重试,这样 B 服务会产⽣ 2 条⼀样的数据。
2. 调⽤ B 服务失败,由于 B 服务不可⽤,重试 3 次依然失败,当前服务在前⾯代码中插⼊到 DB 的⼀条记录,就变成了脏数据。
3. 重试会增加上游对本次调⽤的延迟,如果下游负载较⼤,重试会放⼤下游服务的压⼒。
第⼀个问题:通过让 B 服务的 API ⽀持幂等性来解决。
第⼆个问题:可以通过后台定时脚步去修正数据,但这并不是⼀个很好的办法。
第三个问题:这是通过阻塞式重试提⾼⼀致性、可⽤性,必不可少的牺牲。
阻塞式重试适⽤于业务对⼀致性要求不敏感的场景下。
SpringCloud亿级账户系统TCC分布式事务实战PPT模板
1-3tcc分布式事务的一 致性保障
1-4tcc分布式事务整体 架构图
1-5微信、招商银行亿级 账户系统架构
1-2TCC分布式事务的定 义
1-3TCC分布式事务的一 致性保障
02
第2章亿级账户系统TCC编程模型
第2章亿级账户系统tcc编程模型
2-1账户系统的TCC分布
logo
202x
springcloud亿级账户系统tcc分 布式事务实战
演讲人 202x-11-11
目录
01. 第1章tcc分布式事务快速入门 02. 第2章亿级账户系统tcc编程模型 03. 第3章大型账户系统tcc编程实战
01
第1章TCC分布式事务快速入门
第1章tcc分布式事务 快速入门
1-1分布式事务的常见场 景和解决方案
1
式事务模型一
2-2账户系统的TCC分布
式事务模型二
2
2-3账户系统的TCC分布
3
式事务模型三
2-4账户系统的TCC分布
式事务模型四
4
2-5账户系统的TCC分布
5式事务模ຫໍສະໝຸດ 五2-6账户系统的TCC分布
式事务隔离级别推演
6
03
第3章大型账户系统TCC编程实战
第3章大型账户系统tcc编程实战
3-1TCC账户系统之项目
logo
感谢聆听
1
架构部署图
3-2TCC账户系统之搭建
Eureka注册中心服务端
2
3-3TCC账户系统之搭建
3
Eureka客户端程序
3-4TCC账户系统之数据
库实体创建
4
3-5TCC账户系统之集成
分布式事务处理的挑战与解决方法
分布式事务处理的挑战与解决方法引言:分布式事务处理是当今互联网应用中不可避免的问题之一。
由于数据存储在不同的分布式系统中,要确保数据的一致性和可靠性变得更加困难。
本文将探讨分布式事务处理面临的挑战以及解决方法。
一、挑战:1. 数据一致性问题:在分布式系统中,数据存储在不同的节点上,节点之间存在网络延迟和故障。
当多个节点同时进行写操作时,可能会导致数据不一致的问题。
如何保证数据的一致性成为一个挑战。
2. 并发控制问题:分布式系统中存在大量的并发操作,如何合理地协调多个节点的并发事务,避免冲突和死锁等问题,成为分布式事务处理中难以解决的挑战。
3. 容错性问题:分布式系统中的节点可能出现宕机和网络故障等问题,如何保证在节点故障的情况下仍能够保持系统的正常运行,成为分布式事务处理的关键问题。
二、解决方法:1. 两阶段提交协议(Two-Phase Commit Protocol):两阶段提交协议是一种常用的分布式事务协议,在保证分布式系统数据一致性方面发挥了重要作用。
该协议由协调者和参与者组成,通过预提交和提交两个阶段的协作,实现事务的一致性。
2. 基于消息队列的解决方法:使用消息队列作为中间件,可以将分布式系统中的事务操作进行异步处理,降低了各个节点之间的耦合度,并减少了系统的复杂性。
通过消息队列的可靠投递和重试机制,可以保证事务的执行顺序和数据的一致性。
3. 分布式事务组件:分布式事务组件是针对分布式事务问题所提供的一种解决方案。
这些组件可以提供事务管理、并发控制和容错处理等功能,简化了开发人员在分布式事务处理中的工作。
4. 乐观锁和悲观锁机制:乐观锁和悲观锁是常用的并发控制机制。
乐观锁机制通过版本号和CAS等机制实现,并发控制的粒度较细,适用于并发较少的场景。
悲观锁机制则采用锁的方式实现,并发控制的粒度较粗,适用于并发较高的场景。
5. 数据复制和备份:在分布式系统中,数据复制和备份是常用的保证容错性和数据一致性的手段。
springboot分布式事务实现(XA方式)
springboot分布式事务实现(XA⽅式)关于spring boot ⽀持分布式事务,XA是常⽤的⼀种⽅式。
这⾥把相关的配置记下,⽅便以后使⽤。
⾸先配置两个不同的数据源 : 订单库、持仓库。
/*** Created by zhangjunwei on 2017/8/2.*/@Configurationpublic class DataSourceConfig {/*** db1的 XA datasource** @return*/@Bean(name = "symbolOrder")@Primary@Qualifier("symbolOrder")public AtomikosDataSourceBean symbolOrderBean() {AtomikosDataSourceBean atomikosDataSourceBean = new AtomikosDataSourceBean();atomikosDataSourceBean.setUniqueResourceName("symbolOrder");atomikosDataSourceBean.setXaDataSourceClassName("com.mysql.jdbc.jdbc2.optional.MysqlXADataSource");Properties properties = new Properties();properties.put("URL","jdbc:mysql://localhost:3306/datamanage");properties.put("user", "root");properties.put("password", "123456");atomikosDataSourceBean.setXaProperties(properties);return atomikosDataSourceBean;}/*** db2的 XA datasource** @return*/@Bean(name = "symbolPosition")@Qualifier("symbolPosition")public AtomikosDataSourceBean symbolPositionDataSourceBean() {AtomikosDataSourceBean atomikosDataSourceBean = new AtomikosDataSourceBean();atomikosDataSourceBean.setUniqueResourceName("symbolPosition");atomikosDataSourceBean.setXaDataSourceClassName("com.mysql.jdbc.jdbc2.optional.MysqlXADataSource");Properties properties = new Properties();properties.put("URL", "jdbc:mysql://localhost:3306/symbol_position");properties.put("user", "root");properties.put("password", "123456");atomikosDataSourceBean.setXaProperties(properties);return atomikosDataSourceBean;}/*** transaction manager** @return*/@Bean(destroyMethod = "close", initMethod = "init")public UserTransactionManager userTransactionManager() {UserTransactionManager userTransactionManager = new UserTransactionManager();userTransactionManager.setForceShutdown(true);return userTransactionManager;}/*** jta transactionManager** @return*/@Beanpublic JtaTransactionManager transactionManager() {JtaTransactionManager jtaTransactionManager = new JtaTransactionManager();jtaTransactionManager.setTransactionManager(userTransactionManager());return jtaTransactionManager;}}顺便把相关的依赖贴上,值得注意的是 spring-boot-starter-jta-atomikos 依赖,这是⼀个开源的事务管理器类。
分布式事务实现方式
分布式事务实现方式
分布式事务是指在分布式系统中,多个节点之间的操作需要保证ACID 特性,即原子性、一致性、隔离性和持久性。
由于多个节点的数据可能存在冲突,需要采用一定的方式来保证事务的正确性。
常见的分布式事务实现方式包括:
1. 基于两阶段提交协议(2PC)的实现方式。
2PC 协议包含两个阶段,即投票和提交。
在投票阶段,所有参与者向协调者发送询问消息,询问是否可以提交事务。
在提交阶段,协调者通知所有参与者提交或回滚事务,从而保证事务的一致性。
2. 基于三阶段提交协议(3PC)的实现方式。
3PC 协议在 2PC 协议的基础上引入了准备阶段,即协调者询问参与者是否可以准备提交事务。
在准备阶段,如果某个参与者无法响应,则会超时回滚事务,从而避免了 2PC 协议中的单点故障问题。
3. 基于补偿事务的实现方式。
补偿事务是指在分布式系统中,每个参与者都有自己的本地事务,当整个事务需要回滚时,通过执行相应的补偿操作来回滚事务,从而保证事务的一致性。
4. 基于消息队列的实现方式。
消息队列可以实现异步通信,当需要多个节点之间进行事务操作时,可以通过消息队列来协调各个节点之间的事务操作。
通过设置消息队列的消息确认机制,可以保证事务的一致性。
以上是常见的几种分布式事务实现方式,不同的实现方式适用于不同的场景,需要根据具体情况选择。
基于Spring的事务管理研究
事 务 处 理 , 可 以运 用 其 例 外 阶层 的优 点 。 并 S r g在 事 务 管理 上 可 以提 供 一 致 性 的 模 型 ,你 可 以使 用 声 pn i 明式 的事务管理 , 如此 你 的 组 件 就 不 用 介 入 事 务 处 理 , 由 A P 就 O 介 入 组 件 进 行 事 务 管 理 , 务 管 理 只 需 要 在 定 义 档 中作 一 些 选 项 事 修 改 . 于 组 件并 不介 入 实 质 的 事 务 处 理 , 可 以设 计 得 更 通 用 , 由 它
而 改 变 事 务 处 理 策 略 , 味 着 你 只 要 改 变 定 义 档 的 设 定 , 不 用 意 而
任务失败 , 则第一个任务 回滚到创建新表前的点。
如此 例 所 示 , 将 事 务 限 制 到 一 个 数 据 资 源 , 数 据 库 或 消 可 如 息 队列 。这 些数 据 资 源 通 常提 供 本 地 事 务 功 能 。这 些事 务 由数 据 资源 控 制 . 理起 来 轻 松 高 效 。 务还 可 以跨 越 多个 数 据 资 源 。 管 事 分 布 式 事 务 使 你 得 以 将 出现 在 不 同 系 统 上 的若 干 不 同操 作 合 并 为 单 个 的成 功 或 失 败操 作 。
维普资讯
・
开 发 研 究 与 设 计 技 术 ・ ・ ・ ・・ ・
本 目 任 辑 谢 媛 栏 责 编 : 媛
基于 S r g的事务 管理研 究 pi n
金导 航
( 武汉 警 官 职 业 学 院 , 北 武 汉 4 04 ) 湖 30 0
摘 要 : 文描 述 了事 务 管理 机 制 的 基 本 原理 及 S r g的 简介 , 点 说 明 了 S r g的 编 程 式 事 务 管理 和 声 明 式 事 务 管理 。 本 pn i 重 pn i
springcloud面试题目2020(3篇)
第1篇一、基础知识1. 什么是Spring Cloud?- Spring Cloud是基于Spring Boot的一套微服务架构开发工具集,它提供了一系列在分布式系统环境下的一些常见问题的解决方案,如服务注册与发现、配置管理、负载均衡、断路器、分布式会话等。
2. Spring Cloud的主要组件有哪些?- Eureka:服务注册与发现。
- Config:配置管理。
- Ribbon:客户端负载均衡。
- Hystrix:断路器。
- Feign:声明式HTTP客户端。
-Zuul:API网关。
- Gateway:Spring Cloud Gateway是Spring Cloud生态系统中的网关服务。
- Sleuth:分布式追踪。
- Zipkin:分布式追踪系统。
- Bus:事件总线。
- Stream:消息驱动。
3. 什么是Eureka?它的工作原理是什么?- Eureka是一个高可用性的服务注册和发现中心,它可以让服务注册和发现变得非常容易。
Eureka包含两个组件:Eureka Server和Eureka Client。
- 工作原理:- Eureka Server是一个中央服务,服务实例注册到Eureka Server,Eureka Server维护一个服务注册表。
- Eureka Client通过心跳机制定期向Eureka Server发送心跳,以表明它仍然存活。
- 当Eureka Client需要调用其他服务时,它会从Eureka Server获取服务列表,并调用相应服务。
4. 什么是Ribbon?它如何实现负载均衡?- Ribbon是一个客户端负载均衡器,它可以根据用户指定的规则(如轮询、随机等)来选择一个服务器进行调用。
- 实现方式:- Ribbon维护一个服务器列表,当请求到达时,根据负载均衡策略选择一个服务器。
- Ribbon支持多种负载均衡策略,如轮询、随机、最少连接等。
5. 什么是Hystrix?它如何实现断路器功能?- Hystrix是一个容错库,它可以在微服务架构中实现断路器功能,以防止系统因为某个服务过载而完全崩溃。
分布式事务八股文
分布式事务八股文介绍如下:分布式事务是指在分布式系统中,对多个资源或数据库进行操作时,保持数据的一致性和可靠性的一种机制。
为了满足分布式事务的特性,人们提出了一系列的八股文,用于描述和解决分布式事务的问题。
以下是分布式事务八股文的主要内容:1. ACID原则:ACID是指原子性(Atomicity)、一致性(Consistency)、隔离性(Isolation)和持久性(Durability)。
原子性指一个事务中的操作要么全部成功,要么全部失败;一致性指事务执行前后数据的完整性和约束条件的满足;隔离性指事务之间应该相互隔离,互不干扰;持久性指一旦事务提交,其结果应该是永久性的。
2. CAP定理:CAP定理指出,在分布式系统中,一致性(Consistency)、可用性(Availability)和分区容忍性(Partition Tolerance)这三个特性不可同时满足,最多只能同时满足其中两个。
因此,在设计分布式系统时需要权衡这三个特性,并根据具体需求做出选择。
3. 两阶段提交(2PC):2PC是一种经典的分布式事务协议。
在2PC中,有一个协调者和多个参与者。
在事务提交过程中,协调者先向所有参与者发送准备请求,然后等待参与者的响应。
如果所有参与者都准备好提交,则协调者发送提交请求;否则,协调者发送中止请求。
2PC协议简单易懂,但存在单点故障和阻塞问题。
4. 三阶段提交(3PC):3PC是对2PC的改进和优化。
在3PC中,引入了“预提交”阶段,即协调者会询问参与者是否准备好提交,而不是直接发出准备请求。
这样可以避免了2PC中的阻塞问题,但仍然存在消息丢失和参与者故障导致的问题。
5. 补偿事务:补偿事务是一种容错机制,用于处理分布式事务中的异常情况。
当事务执行过程中出现错误或失败时,可以通过执行补偿操作来回滚已经执行的操作,以保证数据的一致性。
补偿事务相对于传统的回滚事务更加灵活,但需要开发人员手动实现补偿逻辑。
二、springboot项目使用seata实现分布式事务
⼆、springboot项⽬使⽤seata实现分布式事务所有⽂章正⽂在上⼀篇⽂章中,我们简单地了解了⼀下什么是seata。
它是来⾃阿⾥巴巴的内部项⽬不断地发展出来的。
2019年以fescar命名开源于apache开源协议,同年改名为seata。
本⽂将⼊⼿seata,官⽅的⽂档和demo主要以dubbo和springcloud体系的接⼊为主。
本⽂选取springboot作为项⽬构建框架,快速构建⽰例。
环境说明seata的发展还是⽐较快的,⽽版本的更新带来的使⽤变化可能会导致⽂档的过时。
本⽂在阅读官⽅提供的基础上完成。
为了过程顺利最好保持环境版本⼀致,否则你可能得⾃⼰debug问题所在。
1. jdk1.82. mysql8.0.183. springboot 2.2.5.RELEASE4. spring-cloud-alibaba-dependencies 2.2.0.RELEASE5. seata-server v1.1.0当然,版本并不⼀定需要完全⼀样。
⽐如你可以使⽤mysql5+,但是就得强制指定对应的mysql-connector-java.jar的版本。
步骤说明要完成这个⽰例项⽬,需要不少的步骤。
这⾥提前罗列⼀下,⽐较⼼⾥有数1. 搭建springboot项⽬2. 引⼊seata依赖3. 配置1. 添加并修改file.conf和registry.conf配置2. 添加数据源配置3. 数据源添加undo_log表4. 测试1. 数据源添加业务表和数据2. 编写业务代码3. 全局回滚测试搭建springboot项⽬搭建springboot项⽬⽐较简单,本⽂采⽤idea构建了两个项⽬1)user-serviceapplication.properties配置为:server.port=8080server.servlet.context-path=/user-service=user-service2) good-serviceserver.port=8081server.servlet.context-path=/good-service=good-service基础依赖为引⼊seata依赖⾸先Import⼀下dependencies,注意:groupId和官⽅⽂档写的不⼀样,版本是2.2.0.RELEASE <dependencyManagement><dependencies><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-alibaba-dependencies</artifactId><version>2.2.0.RELEASE</version><type>pom</type><scope>import</scope></dependency></dependencies></dependencyManagement>接着引⼊seata的依赖<dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-seata</artifactId></dependency>配置添加并修改file.conf和registry.conf我们需要在resources⽬录下,创建file.conf和registry.conf这两个⽂件。
springbootcloud使用eureka整合分布式事务组件Seata的方法
springbootcloud使⽤eureka整合分布式事务组件Seata的⽅法前⾔近期⼀直在忙项⽬,我也是打⼯仔。
不多说,我们开始玩⼀玩seata。
正⽂什么都不说,我们按照惯例,先上⼀个图(图⾥不规范的使⽤请忽略):简单⼀眼就看出来,⽐我们平时⽤的东西,多了 Seata Server 微服务。
同样这个 Seata Server 微服务,也是需要注册到eureka上⾯去的。
那么我们⾸先就搞⼀搞这个 seata server ,那么剩下的就是⼀些原本的业务服务整合配置了。
该篇⽤的 seata server 版本,⽤的是1.4.1 ,可以去git下载下。
当然,我也是给你们备了的:seata server 1.4.1 某度⽹盘分享地址:提取码: 9at6第⼀步,下载下来解压:第⼆步,创个 seata server ⽤的数据库:CREATE TABLE `branch_table` (`branch_id` bigint(20) NOT NULL,`xid` varchar(128) NOT NULL,`transaction_id` bigint(20) DEFAULT NULL,`resource_group_id` varchar(32) DEFAULT NULL,`resource_id` varchar(256) DEFAULT NULL,`branch_type` varchar(8) DEFAULT NULL,`status` tinyint(4) DEFAULT NULL,`client_id` varchar(64) DEFAULT NULL,`application_data` varchar(2000) DEFAULT NULL,`gmt_create` datetime DEFAULT NULL,`gmt_modified` datetime DEFAULT NULL,PRIMARY KEY (`branch_id`),KEY `idx_xid` (`xid`)) ENGINE=InnoDB DEFAULT CHARSET=utf8;CREATE TABLE `global_table` (`xid` varchar(128) NOT NULL,`transaction_id` bigint(20) DEFAULT NULL,`status` tinyint(4) NOT NULL,`application_id` varchar(32) DEFAULT NULL,`transaction_service_group` varchar(32) DEFAULT NULL,`transaction_name` varchar(128) DEFAULT NULL,`timeout` int(11) DEFAULT NULL,`begin_time` bigint(20) DEFAULT NULL,`application_data` varchar(2000) DEFAULT NULL,`gmt_create` datetime DEFAULT NULL,`gmt_modified` datetime DEFAULT NULL,PRIMARY KEY (`xid`),KEY `idx_gmt_modified_status` (`gmt_modified`,`status`),KEY `idx_transaction_id` (`transaction_id`)) ENGINE=InnoDB DEFAULT CHARSET=utf8;CREATE TABLE `lock_table` (`row_key` varchar(128) NOT NULL,`xid` varchar(96) DEFAULT NULL,`transaction_id` bigint(20) DEFAULT NULL,`branch_id` bigint(20) NOT NULL,`resource_id` varchar(256) DEFAULT NULL,`table_name` varchar(32) DEFAULT NULL,`pk` varchar(36) DEFAULT NULL,`gmt_create` datetime DEFAULT NULL,`gmt_modified` datetime DEFAULT NULL,PRIMARY KEY (`row_key`),KEY `idx_branch_id` (`branch_id`)) ENGINE=InnoDB DEFAULT CHARSET=utf8;创建完后:第三步,修改下 \seata-1.4.1\seata-server-1.4.1\seata\conf ⾥的配置⽂件⼀些信息:1. registry.confok,registry.conf 这⽂件就修改这些配置项。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
Spring分布式事务实现分布式事务是指操作多个数据库之间的事务,spring的org.springframework.transaction.jta.JtaTransactionManager,提供了分布式事务支持。
如果使用WAS的JTA支持,把它的属性改为WebSphere对应的TransactionManager。
在tomcat下,是没有分布式事务的,不过可以借助于第三方软件jotm(Java Open Transaction Manager )和AtomikosTransactionsEssentials实现,在spring中分布式事务是通过jta(jotm,atomikos)来进行实现。
1、/2、/Main/TransactionsEssentials一、使用JOTM例子(1) Dao及实现GenericDao接口:?1 2 3 4 public interface GenericDao {public int save(String ds, String sql, Object[] obj) throws Exception; public intfindRowCount(String ds, String sql);}GenericDaoImpl实现:?1 2 3 4 5 6 7 8 910111213141516171819202122232425262728 public class GenericDaoImpl implements GenericDao{private JdbcTemplatejdbcTemplateA;private JdbcTemplatejdbcTemplateB;public void setJdbcTemplateA(JdbcTemplatejdbcTemplate) {this.jdbcTemplateA = jdbcTemplate;}public void setJdbcTemplateB(JdbcTemplatejdbcTemplate) {this.jdbcTemplateB = jdbcTemplate;}public int save(String ds, String sql, Object[] obj) throws Exception{ if(null == ds || "".equals(ds)) return -1;try{if(ds.equals("A")){return this.jdbcTemplateA.update(sql, obj);}else{return this.jdbcTemplateB.update(sql, obj);}}catch(Exception e){e.printStackTrace();throw new Exception("执行" + ds + "数据库时失败!");}}public intfindRowCount(String ds, String sql) {293031323334353637 if(null == ds || "".equals(ds)) return -1;if(ds.equals("A")){return this.jdbcTemplateA.queryForInt(sql); }else{return this.jdbcTemplateB.queryForInt(sql); }}}(2) Service及实现UserService接口:?1 2 3 public interface UserService {public void saveUser() throws Exception; }UserServiceImpl实现:?1 2 3 4 5 6 7 8 9101112131415161718192021222324 public class UserServiceImpl implements UserService{private GenericDaogenericDao;public void setGenericDao(GenericDaogenericDao) {this.genericDao = genericDao;}public void saveUser() throws Exception {String userName = "user_" + Math.round(Math.random()*10000); System.out.println(userName);StringBuildersql = new StringBuilder();sql.append(" insert into t_user(username, gender) values(?,?); "); Object[] objs = new Object[]{userName,"1"};genericDao.save("A", sql.toString(), objs);sql.delete(0, sql.length());sql.append(" insert into t_user(name, sex) values(?,?); ");objs = new Object[]{userName,"男的"};//值超出范围genericDao.save("B", sql.toString(), objs);}}(3) applicationContext-jotm.xml ?1 2 3 <?xml version="1.0" encoding="UTF-8"?><beans xmlns="/schema/beans" xmlns:xsi="/2001/XMLSchema-instance"4 5 6 7 8 910111213141516171819202122232425262728293031323334353637383940414243444546474849505152 xmlns:context="/schema/context"xmlns:aop="/schema/aop"xmlns:tx="/schema/tx"xsi:schemaLocation="/schema/beans /schema/beans/s /schema/context /schema/context/spring-context-2.5.x /schema/tx /schema/tx/spring-tx-2.5.xsd/schema/aop /schema/aop/spring-aop-2.5.xsd"><description>springJTA</description><!--指定Spring配置中用到的属性文件--><bean id="propertyConfig"class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"><property name="locations"><list><value>classpath:jdbc.properties</value></list></property></bean><!-- JOTM实例--><bean id="jotm" class="org.springframework.transaction.jta.JotmFactoryBean"><property name="defaultTimeout" value="500000"/></bean><!-- JTA事务管理器--><bean id="jtaTransactionManager" class="org.springframework.transaction.jta.JtaTransactionManager"><property name="userTransaction" ref="jotm" /></bean><!-- 数据源A --><bean id="dataSourceA" class="org.enhydra.jdbc.pool.StandardXAPoolDataSource" destroy-method="shutdown"><property name="dataSource"><bean class="org.enhydra.jdbc.standard.StandardXADataSource" destroy-method="shutdown"><property name="transactionManager" ref="jotm"/><property name="driverName" value="${jdbc.driver}"/><property name="url" value="${jdbc.url}"/></bean></property><property name="user" value="${ername}"/><property name="password" value="${jdbc.password}"/></bean><!-- 数据源B --><bean id="dataSourceB" class="org.enhydra.jdbc.pool.StandardXAPoolDataSource" destroy-method="shutdown"><property name="dataSource"><bean class="org.enhydra.jdbc.standard.StandardXADataSource" destroy-method="shutdown"><property name="transactionManager" ref="jotm"/><property name="driverName" value="${jdbc2.driver}"/>535455565758596061626364656667686970717273747576777879808182838485868788899091 <property name="url" value="${jdbc2.url}"/></bean></property><property name="user" value="${ername}"/><property name="password" value="${jdbc2.password}"/></bean><bean id = "jdbcTemplateA"class = "org.springframework.jdbc.core.JdbcTemplate"><property name = "dataSource" ref="dataSourceA"/></bean><bean id = "jdbcTemplateB"class = "org.springframework.jdbc.core.JdbcTemplate"><property name = "dataSource" ref="dataSourceB"/></bean><!-- 事务切面配置--><aop:config><aop:pointcut id="pointCut"expression="execution(* com.logcd.service..*.*(..))"/><!-- 包及其子包下的所有方法--><aop:advisorpointcut-ref="pointCut" advice-ref="txAdvice"/><aop:advisorpointcut="execution(* *mon.service..*.*(..))" advice-ref="txAdvice"/></aop:config><!-- 通知配置--><tx:advice id="txAdvice" transaction-manager="jtaTransactionManager"><tx:attributes><tx:method name="delete*" rollback-for="Exception"/><tx:method name="save*" rollback-for="Exception"/><tx:method name="update*" rollback-for="Exception"/><tx:method name="find*" read-only="true" rollback-for="Exception"/></tx:attributes></tx:advice><bean id="genericDao" class="com.logcd.dao.impl.GenericDaoImpl" autowire="byName"></bean><bean id="userService" class="erServiceImpl" autowire="byName"></bean> </beans>(4) 测试?1 2 3 4 5 6 7 public class TestUserService{private static UserServiceuserService;@BeforeClasspublic static void init(){ApplicationContext app = new ClassPathXmlApplicationContext("applicationContext-jotm.xml");8 9101112131415161718192021 userService = (UserService)app.getBean("userService"); }@Testpublic void save(){System.out.println("begin...");try{userService.saveUser();}catch(Exception e){System.out.println(e.getMessage());}System.out.println("finish...");}}二、关于使用atomikos实现(1) 数据源配置?1 2 3 4 5 6 7 8 91011121314151617181920212223 <bean id="dataSourceA" class="com.atomikos.jdbc.SimpleDataSourceBean" init-method="init" destroy-method="close"> <property name="uniqueResourceName"><value>${datasource.uniqueResourceName}</value></property><property name="xaDataSourceClassName"><value>${database.driver_class}</value></property><property name="xaDataSourceProperties"><value>URL=${database.url};user=${ername};password=${database.password}</value></property><property name="exclusiveConnectionMode"><value>${connection.exclusive.mode}</value></property><property name="connectionPoolSize"><value>${connection.pool.size}</value></property><property name="connectionTimeout"><value>${connection.timeout}</value></property><property name="validatingQuery"><value>SELECT 1</value></property></bean>(2)、事务配置?1 2 <bean id="atomikosTransactionManager" class="erTransactionManager" init-method="init" destroy-method="close">3 4 5 6 7 8 9101112131415161718192021222324252627 <property name="forceShutdown" value="true"/></bean><bean id="atomikosUserTransaction" class="erTransactionImp"><property name="transactionTimeout" value="${transaction.timeout}"/></bean><!-- JTA事务管理器--><bean id="springTransactionManager" class="org.springframework.transaction.jta.JtaTransactionManager"> <property name="transactionManager" ref="atomikosTransactionManager"/><property name="userTransaction" ref="atomikosUserTransaction"/></bean><!-- 事务切面配置--><aop:config><aop:pointcut id="serviceOperation" expression="execution(* *..service*..*(..))"/><aop:advisorpointcut-ref="serviceOperation" advice-ref="txAdvice"/></aop:config><!-- 通知配置--><tx:advice id="txAdvice" transaction-manager="springTransactionManager"><tx:attributes><tx:method name="*" rollback-for="Exception"/></tx:attributes></tx:advice>有关JTAJTA全称为Java Transaction API,顾名思义JTA定义了一组统一的事务编程的接口,这些接口如下:XAResourceXAResource接口是对实现了X/Open CAE规范的资源管理器(Resource Manager,数据库就是典型的资源管理器) 的抽象,它由资源适配器(Resource Apdater) 提供实现。