前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >数据库事务探究

数据库事务探究

作者头像
翎野君
发布2023-05-12 19:47:56
2240
发布2023-05-12 19:47:56
举报
文章被收录于专栏:翎野君翎野君

数据库事务(Database Transaction)

1. 事务是个啥玩意?

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

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

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

3. 事务这玩意能干啥?

一个数据库事务通常包含对数据库进行读或写的一个操作序列。它的存在包含有以下两个目的: 1、为数据库操作提供了一个从失败中恢复到正常状态的方法,同时提供了数据库即使在异常状态下仍能保持一致性的方法。 2、当多个应用程序在并发访问数据库时,可以在这些应用程序之间提供一个隔离方法,以防止彼此的操作互相干扰。

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

commit即提交,表示这个事务的所有操作都执行成功,commit告诉系统,数据库要进入一个新的正确状态,该事务对数据库的所有更新都要确保不因数据库的宕机而丢失。 rollback即回退或回滚,表示事务中有执行失败的操作,这些操作必须被撤销,rollback告诉系统,已发生错误,数据库可能处在不正确的状态,该事务对数据库的部分或所有更新必须被撤销。

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

5. 都有哪些事务?

1.读事务

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

2.写事务

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

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

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

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

7. 隔离级别是个啥?

代码语言:javascript
复制
并发事务所作的修改必须与任何其它并发事务所作的修改隔离。
事务查看数据时数据所处的状态,要么是另一并发事务修改它之前的状态,要么是另一事务修改它之后的状态,事务不会查看中间状态的数据,这称为隔离性。

  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)修改后【未提交】的数据。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2018-02-08,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 数据库事务(Database Transaction)
    • 1. 事务是个啥玩意?
      • 2. 事务都有啥属性特征呢?
        • 3. 事务这玩意能干啥?
          • 4. 追根究底的将事务之前,先问问自己commit和rollback的还知道是干啥的不?
            • 5. 都有哪些事务?
              • 6. 事务并发执行时会产生哪些影响?
                • 7. 隔离级别是个啥?
                  • 8. 啥情况需要隔离,那又咋隔离呢?
                    • 9. 锁机制实现事务隔离
                      • 两把锁
                      • 两把锁的使用规则
                  相关产品与服务
                  数据库
                  云数据库为企业提供了完善的关系型数据库、非关系型数据库、分析型数据库和数据库生态工具。您可以通过产品选择和组合搭建,轻松实现高可靠、高可用性、高性能等数据库需求。云数据库服务也可大幅减少您的运维工作量,更专注于业务发展,让企业一站式享受数据上云及分布式架构的技术红利!
                  领券
                  问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档