数据库事务关注点:
- 特性(ACID):原子性、一致性、隔离性、持久性;
- 问题:脏读、不可重复读、幻读;
- 隔离级别:读未提交、读已提交、可重复读、串行化;
数据库事务的特性:
数据库的事务特性(ACID):
原子性:指事务是一个不可分割的工作单位,事务包含的所有操作要么全部成功,要么全部失败;
一致性:指事务前后,数据库从一个一致性状态变换到另一个一致性状态,比如A和B一共有2000,无论A和B怎么相互转账,他们的总金额都是2000;
隔离性:当多个用户并发操作某一数据时,数据库为每个用户开启一个事务,多个并发事务执行相互隔离,不能被其他事务所影响;
持久性:一个事务一旦提交了,那么数据库中对应数据会产生永久性的变换,即使数据库系统出现故障的情况下,数据也不会丢失;
数据库事务存在的问题:
脏读
一个事务读到另外一个事务还没有提交的数据,称之为脏读。
如果事务A在操作的过程中更新了某条数据V的值,然后事务B读取到了V被事务A修改后的值,这时事务A因为出现异常导致回滚了,数据V又还原为原先的值了,那么事务B刚刚读取到的值其实是不存在的。
不可重复读
一个事务先后读取同一条记录,但两次读取的数据不同,称之为不可重复读。
不可重复读强调的是其他事务对数据进行了修改或者删除,如:事务A先读取了一条数据V,然后事务B将这条数据V进行了更新或者删除操作,并且成功提交了事务,这时事务A再次读取了这条数据V,发现前后2次读取的数据不一致
幻读
指一个事务前后2次查询,读取到的记录数不一致。
相比于不可重复读,它强调的是记录条数的不一致。事务A通过查询读取到了1条记录,接着事务B插入了一条新的数据,并提交了事务,然后事务A再次进行了查询,结果返回了2条记录;
数据库事务的隔离级别:
根据上述现象,SQL定义了四个隔离级别,隔离级别从低到高分别为:读未提交、读已提交、可重复的、串行化。随着隔离级别的提高,数据库的性能逐渐降低。
Read Uncommitted: 读未提交
未提交的写事务不允许其他事务进行修改,但允许其他事务读取该数据,因此会出现脏读、不可重复读的情况
Read Committed: 读已提交
- 未提交的写事务不允许其他事务读取,所以不会出现脏读;
- 读事务允许其他事务访问并修改该行数据,所以可能会出现不可重复读的情况;
Repeatable Read: 可重复度
- 读事务允许其他的读事务对数据进行访问,但是禁止其他的写事务对数据进行操作,所以在事务期间数据不会改变,除非该事务自己修改了数据;
- 允许其他事务进行新增操作,所以会出现幻读的情况;
Serializable:串行化
- 事务隔离的最高级别,要求所有的事务只能一个接着一个的顺序执行,性能最低;
- 可以避免脏读、不可重复读、幻读的出现;
分布式事务
随着业务量不断的上涨,单台引用无法撑起整个项目服务的运行,这时候就涉及到分库分表。同时,会按照业务划分将业务拆分成多个单一项目部署在各个服务器上,每台业务服务连接各自的数据库,这个时候就涉及到了分布式数据一致性问题,需要使用的事务,但是单一事务是无法满足现有的情况,从而衍生到分布式事务。
此处基于SpringCloud+nacos+seata+openfeign进行编写的案例。
环境:
nacos:1.3.2
Seata:1.3.0
Spring.cloud.alibaba.version:2.1.2.RELEASE
注:seata官方从
1.0
版本后不再提供sql脚本,以及nacos推送配置脚本,需要从0.9.0
的版本复制
0.9.0下载地址 1.3.0下载地址
复制到1.3.0版本中。
执行db_store.sql脚本,数据库名为seata
第一步:修改file.conf
文件
注意使用mysql8.0及以上版本的需要更改:
driverClassName ="com.mysql.cj.jdbc.Driver"
第二步:修改registry.conf
文件
修改type为nacos,此处是声明你使用的注册中心
application为seata启动后注册到nacos的服务名
修改:nacos-conf.txt
文件
transport.type=TCP
transport.server=NIO
transport.heartbeat=true
transport.thread-factory.boss-thread-prefix=NettyBoss
transport.thread-factory.worker-thread-prefix=NettyServerNIOWorker
transport.thread-factory.server-executor-thread-prefix=NettyServerBizHandler
transport.thread-factory.share-boss-worker=false
transport.thread-factory.client-selector-thread-prefix=NettyClientSelector
transport.thread-factory.client-selector-thread-size=1
transport.thread-factory.client-worker-thread-prefix=NettyClientWorkerThread
transport.thread-factory.boss-thread-size=1
transport.thread-factory.worker-thread-size=8
transport.shutdown.wait=3
service.vgroupMapping.seata_tx_group=default
service.enableDegrade=false
service.disable=false
service.max.commit.retry.timeout=-1
service.max.rollback.retry.timeout=-1
client.async.commit.buffer.limit=10000
client.lock.retry.internal=10
client.lock.retry.times=30
client.lock.retry.policy.branch-rollback-on-conflict=true
client.table.meta.check.enable=true
client.report.retry.count=5
client.tm.commit.retry.count=1
client.tm.rollback.retry.count=1
store.mode=db
store.file.dir=file_store/data
store.file.max-branch-session-size=16384
store.file.max-global-session-size=512
store.file.file-write-buffer-cache-size=16384
store.file.flush-disk-mode=async
store.file.session.reload.read_size=100
store.db.datasource=druid
store.db.dbType=mysql
store.db.driverClassName=com.mysql.jdbc.Driver
store.db.url=jdbc:mysql://192.168.56.10:3306/seata?useUnicode=true
store.db.user=root
store.db.password=root
store.db.min-conn=1
store.db.max-conn=3
store.db.global.table=global_table
store.db.branch.table=branch_table
store.db.query-limit=100
store.db.lock-table=lock_table
recovery.committing-retry-period=1000
recovery.asyn-committing-retry-period=1000
recovery.rollbacking-retry-period=1000
recovery.timeout-retry-period=1000
transaction.undo.data.validation=true
transaction.undo.log.serialization=jackson
transaction.undo.log.save.days=7
transaction.undo.log.delete.period=86400000
transaction.undo.log.table=undo_log
transport.serialization=seata
transport.compressor=none
metrics.enabled=false
metrics.registry-type=compact
metrics.exporter-list=prometheus
metrics.exporter-prometheus-port=9898
support.spring.datasource.autoproxy=false
启动nacos后执行 :
sh nacos-config.sh 127.0.0.1
执行完成后在nacos控制台可以看到。
启动seata
控制台
项目中引入seata后只需要在相应的业务层加上
@GlobalTransactional注解即可。
项目搭建:
三个模块重点在Seata配置上:
代码
Seata学习:
Seata 是一款开源的分布式事务解决方案,致力于提供高性能和简单易用的分布式事务服务。Seata 将为用户提供了 AT、TCC、SAGA 和 XA 事务模式,为用户打造一站式的分布式解决方案。
AT模式:
- 基于支持本地 ACID 事务的关系型数据库。
- Java 应用,通过 JDBC 访问数据库。
在数据库本地事务隔离级别 读已提交(Read Committed) 或以上的基础上,Seata(AT 模式)的默认全局隔离级别是 读未提交(Read Uncommitted) 。
流程步骤图:
核心组件:
- 事务协调器 TC
维护全局和分支事务的状态,指示全局提交或者回滚。
- 事务管理者 TM
开启、提交或者回滚一个全局事务。
- 资源管理者 RM
管理执行分支事务的那些资源,向TC注册分支事务、上报分支事务状态、控制分支事务的提交或者回滚。
流程:
- TM 请求 TC,开始一个新的全局事务,TC 会为这个全局事务生成一个 XID。
- XID 通过微服务的调用链传递到其他微服务。
- RM 把本地事务作为这个XID的分支事务注册到TC。
- TM 请求 TC 对这个 XID 进行提交或回滚。
- TC 指挥这个 XID 下面的所有分支事务进行提交、回滚。
其分为两阶段提交:
第一阶段:
主要针对于业务数据和回滚日志记录在同一个本地事务中提交,释放本地锁和连接资源。
一阶段本地事务提交前,需要确保先拿到 全局锁 。
拿不到 全局锁 ,不能提交本地事务。
拿 全局锁 的尝试被限制在一定范围内,超出范围将放弃,并回滚本地事务,释放本地锁。
第二阶段:
- 提交异步化,非常快速地完成。
- 回滚通过一阶段的回滚日志进行反向补偿。
最好的学习资源就是官方文档,建议大家仔细研读官方文档和源码。
官方文档:传送门
今天的文章Seat分布式事务学习分享到此就结束了,感谢您的阅读。
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/63132.html