事务ACID原则

原子性:事务中的所有操作,要么全部成功,要么全部失败

一致性:要保证数据库内部完整性约束、声明性约束

隔离性:对同一资源操作的事务不能同时发生

持久性:对数据库做的一切修改将永久保存,不管是否出现故障

一、理论基础

1)CAP理论

1998年,加州大学的计算机科学家 Eric Brewer 提出,分布式系统有三个指标:

Consistency(一致性)

Availability(可用性)

Partition tolerance (分区容错性)

Eric Brewer 说,分布式系统无法同时满足这三个指标。 这个结论就叫做 CAP 定理。

CAP定理- Consistency

Consistency(一致性):用户访问分布式系统中的任意节点,得到的数据必须一致

CAP定理- Availability

Availability (可用性):用户访问集群中的任意健康节点,必须能得到响应,而不是超时或拒绝

CAP定理-Partition tolerance

Partition(分区):因为网络故障或其它原因导致分布式系统中的部分节点与其它节点失去连接,形成独立分区。

Tolerance(容错):在集群出现分区时,整个系统也要持续对外提供服务

2)BASE理论

BASE理论是对CAP的一种解决思路,包含三个思想:

Basically Available (基本可用):分布式系统在出现故障时,允许损失部分可用性,即保证核心可用。

Soft State(软状态):在一定时间内,允许出现中间状态,比如临时的不一致状态。

Eventually Consistent(最终一致性):虽然无法保证强一致性,但是在软状态结束后,最终达到数据一致。

而分布式事务最大的问题是各个子事务的一致性问题,因此可以借鉴CAP定理和BASE理论:

AP模式:各子事务分别执行和提交,允许出现结果不一致,然后采用弥补措施恢复数据即可,实现最终一致。

CP模式:各个子事务执行后互相等待,同时提交,同时回滚,达成强一致。但事务等待过程中,处于弱可用状态

二、分布式事务Seata

1)初识seata

Seata是 2019 年 1 月份蚂蚁金服和阿里巴巴共同开源的分布式事务解决方案。

致力于提供高性能和简单易用的分布式事务服务,为用户打造一站式的分布式解决方案。

官网地址:http://seata.io/,其中的文档中提供了大量的使用说明、源码分析。

2)Seata架构

Seata事务管理中有三个重要的角色:

TC (Transaction Coordinator) - 事务协调者:维护全局和分支事务的状态,协调全局事务提交或回滚。

TM (Transaction Manager) - 事务管理器:定义全局事务的范围、开始全局事务、提交或回滚全局事务。

RM (Resource Manager) - 资源管理器:管理分支事务处理的资源,与TC交谈以注册分支事务和报告分支事务的状态,并驱动分支事务提交或回滚。

Seata提供了四种不同的分布式事务解决方案:

XA模式:强一致性分阶段事务模式,牺牲了一定的可用性,无业务侵入

TCC模式:最终一致的分阶段事务模式,有业务侵入

AT模式:最终一致的分阶段事务模式,无业务侵入,也是Seata的默认模式

SAGA模式:长事务模式,有业务侵入

SeaTa AT模式实战

Seata AT模式实现原理

解析业务SQL,更新业务数据,保存更新前后镜像到undo_log。在业务操作数据库流程中,Seata会基于数据源代理(0.9以后支持自动代理)对原执行SQL进行解析。之后通过本地事务的ACID特性,将这两步操作(保存业务数据前后镜像到undo_log, 更新业务数据)在本地事务中进行提交。

TC服务接收到事务分支的事务状态汇报之后,决定对全局事务进行提交或者回滚,这就是第二阶段。

具体的流程为:

(1) 分支事务收到TC的提交请求之后放入异步队列中,马上返回提交成功的结果;这里不需要同步返回的原因是:TC不需要知道分支事务的结果,因为仅仅只是一步删除UNDO_LOG记录的操作,即使不成功也不会结果造成影响,所以采用异步是有效的方式。

(2) 从异步队列中执行分支提交请求,清理undo_log日志,这里并不需要分支事务的提交了,因为第一阶段中已经提交过了。

理解起来就是:AT模式下的全局事务的提交只需要清理UNDO_LOG记录就行,不需要管分支(本地)事务的提交结果!

下载地址:https://github.com/seata/seata/releases

修改seata1.6.1/seata/conf/application.yml内容,由于使用nacos作为注册中心主要seata的config、registry、store

# 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

#

# http://www.apache.org/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.

server:

port: 7091

spring:

application:

name: seata-server

logging:

config: classpath:logback-spring.xml

file:

path: ${user.home}/logs/seata

extend:

logstash-appender:

destination: 127.0.0.1:4560

kafka-appender:

bootstrap-servers: 127.0.0.1:9092

topic: logback_to_logstash

console:

user:

username: seata

password: seata

seata:

config:

# support: nacos, consul, apollo, zk, etcd3

type: nacos

nacos:

server-addr: 127.0.0.1:8848

namespace:

group: DEFAULT_GROUP

##if use MSE Nacos with auth, mutex with username/password attribute

#access-key: ""

#secret-key: ""

data-id: seataServer.properties

registry:

# support: nacos, eureka, redis, zk, consul, etcd3, sofa

type: nacos

nacos:

application: seata-server

server-addr: 127.0.0.1:8848

namespace:

group: DEFAULT_GROUP

##if use MSE Nacos with auth, mutex with username/password attribute

#access-key: ""

#secret-key: ""

store:

# support: file 、 db 、 redis

mode: db

db:

datasource: druid

db-type: mysql

driver-class-name: com.mysql.jdbc.Driver

url: jdbc:mysql://127.0.0.1:3306/seata?rewriteBatchedStatements=true

user: root

password: feng02140.0

min-conn: 10

max-conn: 100

global-table: global_table

branch-table: branch_table

lock-table: lock_table

distributed-lock-table: distributed_lock

query-limit: 1000

max-wait: 5000

security:

secretKey: SeataSecretKey0c382ef121d778043159209298fd40bf3850a017

tokenValidityInMilliseconds: 1800000

ignore:

urls: /,/**/*.css,/**/*.js,/**/*.html,/**/*.map,/**/*.svg,/**/*.png,/**/*.ico,/console-fe/public/**,/api/v1/auth/login

根据seata1.6.1/seata/script/server/db/mysql.sql建数据库表seata

在nacos中新增配置seataServer.properties

# 数据存储方式,db代表数据库

store.mode=db

store.db.datasource=druid

store.db.dbType=mysql

store.db.driverClassName=com.mysql.cj.jdbc.Driver

store.db.url=jdbc:mysql://127.0.0.1:3306/seata?useUnicode=true&rewriteBatchedStatements=true&serverTimezone=GMT

store.db.user=root

store.db.password=feng02140.0

store.db.minConn=5

store.db.maxConn=30

store.db.globalTable=global_table

store.db.branchTable=branch_table

store.db.queryLimit=100

store.db.lockTable=lock_table

store.db.maxWait=5000

# 事务、日志等配置

server.recovery.committingRetryPeriod=3000

server.recovery.asynCommittingRetryPeriod=3000

server.recovery.rollbackingRetryPeriod=3000

server.recovery.timeoutRetryPeriod=3000

server.maxCommitRetryTimeout=-1

server.maxRollbackRetryTimeout=-1

server.rollbackRetryTimeoutUnlockEnable=false

server.undo.logSaveDays=7

server.undo.logDeletePeriod=86400000

# 客户端与服务端传输方式

transport.serialization=seata

transport.compressor=none

# 关闭metrics功能,提高性能

metrics.enabled=false

metrics.registryType=compact

metrics.exporterList=prometheus

metrics.exporterPrometheusPort=9898

Nacos中新建service.vgroupMapping.order-service

启动seata

访问后台http://127.0.0.1:7091/#/login

账号:seata 密码:seata

父POM引入

io.seata

seata-all

${seata.version}

order以及store服务引入

io.seata

seata-spring-boot-starter

${seata.version}

com.alibaba.cloud

spring-cloud-starter-alibaba-seata

io.seata

seata-all

seata-spring-boot-starter

io.seata

order服务中配置

seata:

application-id: order-service

tx-service-group: order-service

registry:

type: nacos

nacos:

application: seata-server

server-addr: 127.0.0.1:8848

username: nacos

password: nacos

group: DEFAULT_GROUP

namespace:

config:

type: nacos

nacos:

server-addr: 127.0.0.1:8848

username: nacos

password: nacos

group: DEFAULT_GROUP

namespace:

service:

vgroupMapping:

order-service: default

store服务中配置

seata:

application-id : store-service

tx-service-group: order-service

registry:

type: nacos

nacos:

application: seata-server

server-addr: 127.0.0.1:8848

username: nacos

password: nacos

group: DEFAULT_GROUP

namespace:

config:

type: nacos

nacos:

server-addr: 127.0.0.1:8848

username: nacos

password: nacos

group: DEFAULT_GROUP

namespace:

service:

vgroupMapping:

order-service: default

service.vgroupMapping 后的order-service为事务组名称,对应Nacos的配置service.vgroupMapping.order-service中的order-service

对应tx-service-group 后的value

两个服务需要配置同一个事务组

在order服务接口上添加@GlobalTransactional(name = "order",rollbackFor = Exception.class)

使用postman访问,模拟库存不足的情况,库存不足将抛出RunTimeException.修改库存为0

order存在两个订单

发送请求

发现库存不足,订单创建失败,事务被回滚.查看数据库

因库存不足order并未被创建

[遇到的小问题]:store服务在接口层面不能直接catch异常,不然会无法回滚.

相关文章

评论可见,请评论后查看内容,谢谢!!!
 您阅读本篇文章共花了: