内容简介:一般来说,原子是指不能分解成小部分的东西。这个词在计算的不同分支中意味着相似但又微妙不同的东西。例如,在多线程编程中,如果一个线程执行一个原子操作,这意味着另一个线程无法看到该操作的一半结果。系统只能处于操作之前或操作之后的状态,而不是介于两者之间的状态。ACID一致性的概念是,对数据的一组特定陈述必须始终成立。即不变量(invariants)。例如,在会计系统中,所有账户整体上必须借贷相抵。如果一个事务开始于一个满足这些不变量的有效数据库,且在事务处理期间的任何写入操作都保持这种有效性,那么可以确定,不变
一般来说,原子是指不能分解成小部分的东西。这个词在计算的不同分支中意味着相似但又微妙不同的东西。例如,在多线程编程中,如果一个线程执行一个原子操作,这意味着另一个线程无法看到该操作的一半结果。系统只能处于操作之前或操作之后的状态,而不是介于两者之间的状态。
一致性(consistency)
ACID一致性的概念是,对数据的一组特定陈述必须始终成立。即不变量(invariants)。例如,在会计系统中,所有账户整体上必须借贷相抵。如果一个事务开始于一个满足这些不变量的有效数据库,且在事务处理期间的任何写入操作都保持这种有效性,那么可以确定,不变量总是满足的。
但是,一致性的这种概念取决于应用程序对不变量的观念,应用程序负责正确定义它的事务,并保持一致性。这并不是数据库可以保证的事情:如果你写入违反不变量的脏数据,数据库也无法阻止你。 (一些特定类型的不变量可以由数据库检查,例如外键约束或唯yi约束,但是一般来说,是应用程序来定义什么样的数据是有效的,什么样是无效的。—— 数据库只管存储。
隔离性(Isolation)
大多数数据库都会同时被多个客户端访问。如果它们各自读写数据库的不同部分,这是没有问题的,但是如果它们访问相同的数据库记录,则可能会遇到并发问题(竞争条件(race conditions))。
持久性(Durability)
数据库系统的目的是,提供一个安全的地方存储数据,而不用担心丢失。持久性 是一个承诺,即一旦事务成功完成,即使发生硬件故障或数据库崩溃,写入的任何数据也不会丢失。
问题
脏读问题破坏隔离性
回滚确保一致性不被破坏
弱隔离级别
读-提交级别
- 防止脏读
- 防止脏写
脏读
用户2只有在用户1的事务已经提交后才能看到x的新值。
脏写
如果事务更新多个对象,脏写会导致不好的结果。例如,考虑 图7-5,图7-5 以一个二12x手3x车2销3售4网5站x为例,Alice和Bob两个人同时试图购买同一辆车。购买汽车需要两次数据库写入:网站上的商品列表需要更新,以反映买家的购买,销23售434发534票需要发送给买家。
一大段话删了,二分法排查出来有什么敏感词,但我是真看不出来.........
实现读-提交级别
数据库通过使用行锁(row-level lock) 来防止脏写:当事务想要修改特定对象(行或文档)时,它必须首先获得该对象的锁。然后必须持有该锁直到事务被提交或中止。一次只有一个事务可持有任何给定对象的锁;如果另一个事务要写入同一个对象,则必须等到第yi个事务提交或中止后,才能获取该锁并继续。这种锁定是读已提交模式(或更强的隔离级别)的数据库自动完成的。
如何防止脏读?一种选择是使用相同的锁,并要求任何想要读取对象的事务来简单地获取该锁,然后在读取之后立即再次释放该锁。这能确保不会读取进行时,对象不会在脏的状态,有未提交的值(因为在那段时间锁会被写入该对象的事务持有)。
但是要求读锁的办法在实践中效果并不好。因为一个长时间运行的写入事务会迫使许多只读事务等到这个慢写入事务完成。这会损失只读事务的响应时间,并且不利于可操作性:因为等待锁,应用某个部分的迟缓可能由于连锁效应,导致其他部分出现问题。
出于这个原因,大多数数据库使用延迟的方式防止脏读:对于写入的每个对象,数据库都会记住旧的已提交值,和由当前持有写入锁的事务设置的新值。 当事务正在进行时,任何其他读取对象的事务都会拿到旧值。 只有当新值提交后,事务才会切换到读取新值。其实也jiu是一个快照!
快照级别隔离
不可重复读/读倾斜
是指在一个事务内,多次读同一数据。在这个事务还没有结束时,另外一个事务也访问该同一数据。那么,在第yi个事务中的两 次读数据之间,由于第二个事务的修改,那么第yi个事务两次读到的的数据可能是不一样的。这样jiu发生了在一个事务内两次读到的数据是不一样的,因此称为是不 可重复读。例如,一个编辑人员两次读取同一文档,但在两次读取之间,作者重写了该文档。当编辑人员第二次读取文档时,文档已更改。原始读取不可重复
MVCC(多版本并发控制)
解决只读事务的不可重复读问题,实现了可重复读级别隔离
防止更新丢失
针对事务的重复写问题
原子写操作
显式加锁操作
自动检测更新丢失
原子操作和锁是通过强制读取-修改-写入序列按顺序发生,来防止丢失更新的方法。另一种方法是允许它们并行执行,如果事务管理器检测到丢失更新,则中止事务并强制它们重试其读取-修改-写入序列。
这种方法的一个优点是,数据库可以结合快照隔离高xiao地执行此检查。事实上,PostgreSQL的可重复读,Oracle的可串行化和SQL Server的快照隔离级别,都会自动检测到丢失更新,并中止惹麻烦的事务。
写倾斜和幻读
幻读
给出 mysql 幻读的比较形象的场景:users: id 主键1、T1:select * from users where id = 1;2、T2:insert into users
( id
, name
) values (1, 'big cat');3、T1:insert into users
( id
, name
) values (1, 'big cat');T1 :主事务,检测表中是否有 id 为 1 的记录,没有则插入,这是我们期望的正常业务逻辑。T2 :干扰事务,目的在于扰乱 T1 的正常的事务执行。在 RR 隔离级别下,1、2 是会正常执行的,3 则会报错主键冲突,对于 T1 的业务来说是执行失败的,这里 T1 jiu是发生了幻读,因为T1读取的数据状态并不能支持他的下一步的业务,见了gui一样。
来源:知乎 www.zhihu.com/question/47…
写倾斜
导致写倾斜的幻读 所有这些例子都遵循类似的模式:
一个SELECT查询找出符合条件的行,并检查是否符合一些要求。(例如:至少有两名医生在值班;不存在对该会议室同一时段的预定;棋盘上的位置没有被其他棋子占据;用户名还没有被抢注;账户里还有足够余额)
按照第个yi查询的结果,应用代码决定是否继续。(可能会继续操作,也可能中止并报错)
如果应用决定继续操作,jiu执行写入(插入、更新或删除),并提交事务。
这个写入的效果改变了步骤2 中的先决条件。换句话说,如果在提交写入后,重复执行一次步骤1 的SELECT查询,将会得到不同的结果。因为写入改变符合搜索条件的行集(现在少了一个医生值班,那时候的会议室现在已经被预订了,棋盘上的这个位置已经被占据了,用户名已经被抢注,账户余额不够了)。
这些步骤可能以不同的顺序发生。例如可以首先进行写入,然后进行SELECT查询,zui后根据查询结果决定是放弃还是提交。
以上所述就是小编给大家介绍的《《数据密集型应用设计》之事务》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:- 设计数据密集型应用(六-七):分片、事务
- 设计数据密集型应用(6-7):分片、事务
- 设计数据密集型应用(1-2)
- 计算密集型服务的负载均衡策略
- 设计数据密集型应用(四):Encoding and Evolution
- [译] 设计数据密集型应用(三):Storage and Retrieval
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。