数据库事务探究

本文涉及的产品
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 RDS MySQL,集群版 2核4GB 100GB
推荐场景:
搭建个人博客
RDS MySQL Serverless 高可用系列,价值2615元额度,1个月
简介: 数据库事务探究

数据库事务(Database Transaction)

1. 事务是个啥玩意?

数据库事务是指作为单个逻辑工作单元执行的一系列操作,要么完全地执行,要么完全地不执行。 
事务处理可以确保除非事务性单元内的所有操作都成功完成,否则不会永久更新面向数据的资源。
通过将一组相关操作组合为一个要么全部成功要么全部失败的单元,可以简化错误恢复并使应用程序更加可靠。

2. 事务都有啥属性特征呢?

  1. 原子性(Atomicity):事务作为一个整体被执行,包含在其中的对数据库的操作要么全部被执行,要么都不执行。
  2. 一致性(Consistency):事务应确保数据库的状态从一个一致状态转变为另一个一致状态。一致状态的含义是数据库中的数据应满足完整性约束。
  3. 隔离性(Isolation):多个事务并发执行时,一个事务的执行不应影响其他事务的执行。
  4. 持久性(Durability):一个事务一旦提交,他对数据库的修改应该永久保存在数据库中。

3. 事务这玩意能干啥?

一个数据库事务通常包含对数据库进行读或写的一个操作序列。它的存在包含有以下两个目的:


1、为数据库操作提供了一个从失败中恢复到正常状态的方法,同时提供了数据库即使在异常状态下仍能保持一致性的方法。
2、当多个应用程序在并发访问数据库时,可以在这些应用程序之间提供一个隔离方法,以防止彼此的操作互相干扰。

4. 追根究底的将事务之前,先问问自己commit和rollback的还知道是干啥的不?

commit即提交,表示这个事务的所有操作都执行成功,commit告诉系统,数据库要进入一个新的正确状态,该事务对数据库的所有更新都要确保不因数据库的宕机而丢失。

rollback即回退或回滚,表示事务中有执行失败的操作,这些操作必须被撤销,rollback告诉系统,已发生错误,数据库可能处在不正确的状态,该事务对数据库的部分或所有更新必须被撤销。

commit的作用不是把缓存/内存中的数据更新/同步到数据库。
commit 之前,数据已经提交到服务器了,只是写在日志里,没有正式提交。所以可以被另外的客户端读取。

5. 都有哪些事务?

1.读事务

如果你一次执行单条查询语句,则没有必要启用事务支持,数据库默认支持SQL执行期间的读一致性;

如果你一次执行多条查询语句,例如统计查询,报表查询,在这种场景下,多条查询SQL必须保证整体的读一致性,否则,在前条SQL查询之后,后条SQL查询之前,数据被其他用户改变,则该次整体的统计查询将会出现读数据不一致的状态,此时,应该启用事务支持。

2.写事务

很好理解,如银行转账A用户需要扣钱B用户需要加钱。

6. 事务并发执行时会产生哪些影响?

首先程序是可以并发执行的,同样,在MySQL中,一个表可以由两个或多个进程同时来读写数据。

比如,此时有两个进程来读数据,这也没什么问题,允许。但是如果一个进程在读某一行的数据的过程中,另一个在进程又往这一行里面写数据(改、删),那结果会是如何?同样,如果两个进程都同时对某一行数据进行更改,以谁的更改为准?那结果又会怎样,不敢想象,是不是数据就被破坏掉了。所以此时是冲突的。

某一时刻同时发来3000个请求指定进程,进程中单线程执行的话那相当与3000个读写操作同时发生。
一个进程中开3000个线程同时对数据库进行读写操作。

7. 隔离级别是个啥?

并发事务所作的修改必须与任何其它并发事务所作的修改隔离。
事务查看数据时数据所处的状态,要么是另一并发事务修改它之前的状态,要么是另一事务修改它之后的状态,事务不会查看中间状态的数据,这称为隔离性。
  1. 读未提交:(Read Uncommitted)
  2. 读已提交(Read Committed) 大多数数据库默认的隔离级别
  3. 可重复读(Repeatable-Read) mysql数据库所默认的级别
  4. 序列化(serializable)

上面四中都是事务并发时可能会产生的影响,按照影响性大小的不同又被称为事务的隔离级别。

8. 啥情况需要隔离,那又咋隔离呢?

既然会冲突就要想办法解决,靠谁来解决,这时候就是靠锁机制来维护了。怎么使用锁来使他们不冲突?

1.丢失更新

当两个或多个事务选择同一行,然后基于最初选定的值更新该行时,会发生丢失更新问题。每个事务都不知道其它事务的存在。最后的更新将重写由其它事务所做的更新,这将导致数据丢失。

如:两个事务都需要更新同一条记录中的Name字段

时间点 事务A 事务B
1 事务开始  
2 读取Name=‘张三’ 事务开始
3   读取Name=‘张三’
4 更新Name=‘毛蛋’  
5 事务结束 更新Name=‘狗子’
6   事务结束

事务A:‘老子的毛蛋怎么没了!’

事实上Mysql数据库会在事务里面默认添加写锁,上面的现象是没法重现的。

2.读未提交(脏读)

脏读又称无效数据读出。一个事务读取另外一个事务还没有提交的数据叫脏读。

事务T1修改了一行数据,但是还没有提交,这时候事务T2读取了被事务T1修改后的数据,之后事务T1因为某种原因Rollback了,那么事务T2读取的数据就是脏的。

时间点 事务A 事务B
1 事务开始  
2 读取Name=‘张三’ 事务开始
3   更新Name=‘狗子’
4 读取Name=‘狗子’  
5   事务回滚Name=‘张三’
6 读取Name=‘张三’  
7 事务结束 事务结束

事务A:‘中间咋突然冒出个狗子,真纳闷!’

解决办法:把数据库的事务隔离级别调整到READ_COMMITTED

3.读已提交(不可重复读)

不可重复读是指在同一个事务内,两个相同的查询返回了不同的结果。
事务T1读取某一数据,事务T2读取并修改了该数据,T1为了对读取值进行检验而再次读取该数据,便得到了不同的结果。

时间点 事务A 事务B
1 事务开始  
2 读取Name=‘张三’ 事务开始
3   更新Name=‘狗子’
4 读取Name=‘张三’  
5   事务结束
6 读取Name=‘狗子’  
7 事务结束  

事务A:‘在我的一个事务里先后读取同样的记录结果却不一样,真奇怪。’

解决办法:把数据库的事务隔离级别调整到REPEATABLE_READ

4.幻读

和可重复读类似,但是事务二的数据操作仅仅是插入和删除,不是修改数据,读取的记录数量前后不一致。

按一定条件从数据库中读取了某些记录后,T2删除了其中部分记录,当T1再次按相同条件读取数据时,发现某些记录消失。

T1按一定条件从数据库中删除某些数据记录后,T2插入了一些记录,当T1再次按相同条件读取数据时,发现多了一些记录。

不可重复读侧重表达 读-读,幻读则是说 读-写,用写来证实读的是鬼影。

时间点 事务A 事务B
1 事务开始  
2 查询到有两个人的Name=‘张三’ 事务开始
3 将所有Name=‘张三’的Score变成100分  
4   插入Name=‘张三’且Score=60
5 读取到3条Name=‘张三’且有一条得分为60 事务结束
6 事务结束  

事务A:‘怎么多出来一条数据?还是60分,难不成我刚才眼花了,还是产生了幻觉?’

解决办法:把数据库的事务隔离级别调整到SERIALIZABLE_READ

9. 锁机制实现事务隔离

两把锁

🔐排他锁:被加锁的对象只能被持有锁的事务读取和修改,其他事务无法在该对象上加其他锁,也不能读取和修改该对象。

🔐共享锁:被加锁的对象可以被持锁事务读取,但是不能被修改,其他事务也可以在上面再加共享锁。

特别的,对共享锁:如果两个事务对同一个资源上了共享锁,事务A想更新该数据,那么它必须等待事务B释放其共享锁。

【共享锁=S锁】又称读锁,若事务T对数据对象A加上S锁,则事务T可以读A但不能修改A,其他事务只能再对A加S锁,而不能加X锁,直到T释放A上的S锁。这保证了其他事务可以读A,但在T释放A上的S锁之前不能对A做任何修改。

【排他锁=X锁】又称写锁。若事务T对数据对象A加上X锁,事务T可以读A也可以修改A,其他事务不能再对A加任何锁,直到T释放A上的锁。这保证了其他事务在T释放A上的锁之前不能再读取和修改A。

两把锁的使用规则

在运用🔐排他锁和🔐共享锁对数据对象加锁时,还需要约定一些规则,例如何时申请 排他锁 或 共享锁、持锁时间、何时释放等。称这些规则为封锁协议(Locking Protocol)。对封锁方式规定不同的规则,就形成了各种不同的封锁协议。

何时用锁,用什么锁,什么时候释放锁,都是数据库层面的事情,不需要我们去关心。以及下面要讲到的封锁协议,都是数据库已经拟定好的了,什么时候对行加锁,对表加锁在协议中指定好了,我们到时候只需选择事务的隔离级别就好了。

一级封锁协议(对应read uncommitd)

一级封锁协议是:事务在对需要修改的数据上面(就是在发生修改的瞬间) 对其加共享锁(其他事务不能更改,但是可以读取-导致“脏读”),直到事务结束才释放。事务结束包括正常结束(COMMIT)和非正常结束(ROLLBACK)。

一级封锁协议不能避免 丢失更新,脏读,不可重复读,幻读!

二级封锁协议(对应read commit)

二级封锁协议是:

1)事务在对需要更新的数据上(就是发生更新的瞬间)加排他锁(直到事务结束),防止其他事务读取未提交的数据,这样,也就避免了 “脏读” 的情况。

2)事务对当前被读取的数据上面加共享锁(当读到时加上共享锁),一旦读完该行,立即释放该该行的共享锁。

二级封锁协议除防止了“脏读”数据,但是不能避免 丢失更新,不可重复读,幻读 。

二级封锁协议中,由于读完数据后立即释放共享锁,所以它不能避免可重复读,同时它也不能避免丢失更新,如果事务A、B同时获取资源X,然后事务A先发起更新记录X,那么事务B 将等待事务A执行完成,然后获得记录X 的排他锁,进行更改。这样事务A的更新将会被丢失。


三级封锁协议(对应reapetable read)

三级封锁协议是:二级封锁协议加上事务在读取数据的瞬间必须先对其加共享锁 ,但是直到事务结束才释放,这样保证了可重复读(既是其他的事务职能读取该数据,但是不能更新该数据)。 

三级封锁协议除防止了“脏”数据 和不可重复读 。但是这种情况不能避免 幻读和丢失更新的情况。

在事务A没有完成之前,事务B可以新增数据,那么当事务A再次读取的时候,事务B新增的数据会被读取到,这样,在该封锁协议下,幻读就产生了。

如果事务A和事务B同时读取了资源X=100,同样,如果事务A先对X进行更新X=X+100,等待事务A执行完成X=200,那么事务B 获得X的排他锁,进行更新X=X+200,然后提交 X=300,同样A的更新被B所覆盖!

最强封锁协议(对应Serialization)

四级封锁协议是对三级封锁协议的增强,其实现机制也最为简单,直接对 事务中 所 读取 或者 更改的数据所在的表加表锁,也就是说,其他事务不能 读写 该表中的任何数据。这样所有的 脏读,不可重复读,幻读 ,都得以避免!

附:Mysql中不同级别锁的介绍

页级:引擎 BDB。

表级:引擎 MyISAM , 理解为锁住整个表,可以同时读,写不行

行级:引擎 INNODB , 单独的一行记录加锁

表级,直接锁定整张表,在你锁定期间,其它进程无法对该表进行写操作。如果你是写锁,则其它进程则读也不允许

行级,,仅对指定的记录进行加锁,这样其它进程还是可以对同一个表中的其它记录进行操作。

页级,表级锁速度快,但冲突多,行级冲突少,但速度慢。所以取了折衷的页级,一次锁定相邻的一组记录。

备注:Mysql的默认隔离级别是 可重复读(Repeatable-Read)

当设置事务隔离级别为Read Ucommitted的时候,一个事务(A)能读取到另一个事务(B)修改后【未提交】的数据。


相关实践学习
如何在云端创建MySQL数据库
开始实验后,系统会自动创建一台自建MySQL的 源数据库 ECS 实例和一台 目标数据库 RDS。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助     相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
目录
相关文章
|
5天前
|
SQL 数据库 数据安全/隐私保护
SQL Server数据库Owner导致事务复制log reader job无法启动的解决办法
【8月更文挑战第14天】解决SQL Server事务复制Log Reader作业因数据库所有者问题无法启动的方法:首先验证数据库所有者是否有效并具足够权限;若非,使用`ALTER AUTHORIZATION`更改为有效登录名。其次,确认Log Reader使用的登录名拥有读取事务日志所需的角色权限。还需检查复制配置是否准确无误,并验证Log Reader代理的连接信息及参数。重启SQL Server Agent服务或手动启动Log Reader作业亦可能解决问题。最后,审查SQL Server错误日志及Windows事件查看器以获取更多线索。
|
2月前
|
存储 关系型数据库 MySQL
MySQL数据库进阶第六篇(InnoDB引擎架构,事务原理,MVCC)
MySQL数据库进阶第六篇(InnoDB引擎架构,事务原理,MVCC)
|
3月前
|
SQL 关系型数据库 MySQL
使用关系型数据库事务的例子
【5月更文挑战第12天】本文介绍了设置MySQL事务的三种方式:全局、当前session和下一个事务,并提供了示例代码展示如何开始事务和设置隔离级别。还简述了引擎设置和数据源DSN格式。最后,讨论了SQL优化策略,包括选择合适的存储引擎、优化字段数据类型、建立索引、避免全表扫描等。
264 4
使用关系型数据库事务的例子
|
3月前
|
存储 关系型数据库 MySQL
了解如何在关系型数据库中处理事务
【5月更文挑战第12天】数据库事务确保数据的ACID特性,即原子性、一致性、隔离性和持久性。它们用于一组操作,要么全部成功,要么全部不执行,防止数据不一致。MySQL的InnoDB存储引擎严格支持事务。MySQL默认隔离级别为REPEATABLE READ
62 3
|
28天前
|
存储 SQL 关系型数据库
数据库事务:确保数据完整性的关键20
【7月更文挑战第20天】事务是数据库操作的基本逻辑单位,确保数据一致性。ACID原则包括:原子性(操作全成或全败),一致性(事务前后数据合法性),隔离性(并发操作互不影响),持久性(提交后更改永久保存)。MySQL的InnoDB引擎支持事务,通过undo log实现回滚,redo log确保数据持久化。开启事务可使用`BEGIN`或`START TRANSACTION`,提交`COMMIT`,回滚`ROLLBACK`。
148 70
|
1月前
|
SQL 关系型数据库 MySQL
乐观锁在分布式数据库中与事务隔离级别结合使用
乐观锁在分布式数据库中与事务隔离级别结合使用
|
14天前
|
缓存 关系型数据库 MySQL
MySQL调优秘籍曝光!从索引到事务,全方位解锁高可用秘诀,让你的数据库性能飞起来!
【8月更文挑战第6天】MySQL是顶级关系型数据库之一,其性能直接影响应用的高可用性与用户体验。本文聚焦MySQL的高性能调优,从索引设计到事务管理,逐一解析。介绍如何构建高效索引,如联合索引`CREATE INDEX idx_order_customer ON orders(order_id, customer_id);`,以及索引覆盖查询等技术。
39 0
|
2月前
|
关系型数据库 MySQL 数据库
MySQL数据库基础第四篇(多表查询与事务)
MySQL数据库基础第四篇(多表查询与事务)
|
2月前
|
SQL 关系型数据库 MySQL
MySQL数据库——事务操作-begin-commit-rollback
MySQL数据库——事务操作-begin-commit-rollback
30 1
|
2月前
|
SQL 关系型数据库 MySQL
MySQL数据库——基础篇总结(概述、SQL、函数、约束、多表查询、事务)一
MySQL数据库——基础篇总结(概述、SQL、函数、约束、多表查询、事务)一
34 5