数据库笔记

脏写: 事务一修改了某一个值,但是尚未提交,事务二又修改了这个值,并提交,这就是脏写,也就是后写的操作覆盖了较早的写入
    解决: 一般是延迟后一个事务的写操作,实现中采用行锁
脏读: 事务一修改了某个值,但是尚未提交,事务二读取到了事务一修改后的值,后面如果事务一回滚了,那么事务二就读取到了一个错误的值
    解决: 对每个更新对象,数据库都会保存一个旧值和当前持锁事务的新值两个版本,提交之前,其他事务读取旧值,提交之后,用新值替换旧值

不可重复读(读倾斜): 事务一读取了数据A,之后根据查询结果做了操作,过程中事务二修改了数据A,并提交了事务,后面事务一又读了一次数据A,发现值不一样了
    解决: 数据库保存对象多个不同的提交版本,也就是多版本并发控制(MVCC)
    问题: MVCC如何支持索引: 
        1. PostGreSQL:把同一个对象的不同版本放到同一个内存页面上
        2. BTree结构的,采用写时复制技术,需要更新时,不修改现有的页面,总是创建一个新的修改副本,拷贝必要的内容, 然后让父节点,或者递归向上知道树的root节点,都指向新的节点
                那些不受更新影响的页面都不需要复制,保持不变并被父节点所指向
并发写冲突: 多个事务同事更新一个对象,导致的更新丢失,比如在递增计数器和账户的时候
    解决方案: 1. 原子写: 例如set value = value+1, 通常采用对读取对象加独占锁的方式来实现,这种技术有时被称为游标稳定性,另一种实现方式是强制所有的原子操作都在单线程上执行
              2. 显示加锁:  for update 指令指示数据库对返回的所有结果行要加锁
              3. 自动检测更新丢失: 数据库完全可以借助快照级别隔离来高效的执行检查,PostGreSQL的可重复读,Oracle的可串行化以及SQL Server的快照级别隔离,都可以自动检测
                    何时发生了更新丢失,然后会终止违规的事务。但是Mysql/Innodb的可重复读却并不检测更新丢失。
    
幻读(写倾斜):可以看作更广义的更新丢失,两个事务读取相同的一组对象,然后更新其中一部分;不同事务可能更新不同的对象,则可能发生写倾斜;二不同对象如果更新的是同一个对象
                则可能发生脏写或更新丢失
    解决: 1. 显示加锁:  for update 指令指示数据库对返回的所有结果行要加锁
          2. 串行化: 保证即使事务可能并行执行,但最终的结果与每次执行一个即串行化执行结果相同。
    产生条件(模式):
        1. 首先输入一些匹配条件,即采用SELECT查询所有满足条件的行
        2. 根据查询的结果,应用层代码来决定下一步操作
        3. 发起数据库写入(INSERT,UPDATE或DELETE)并提交事务,而这个写操作会改变步骤2作出决定的前提条件
        换句话说,就是如果提交步骤3的事务,再重复执行步骤1的查询,就会返回完全不同的结果,这样就可能会导致幻读

串行化: 目前大多数可提供可串行化的数据库都是用了以下三种技术之一:
    1. 严格按照串行顺序执行, ①H-Store,Redis和Datomic等采用串行化方式执行事务。可以避免锁开销,但是其吞吐量上限是单个CPU核的吞吐量。②存储过程 ,但是语言跟不上,缺乏函数库
    2. 两阶段锁定: 第一阶段:执行之前获取锁,第二阶段:事务结束释放锁
        解释: ①如果事务A已经读取了某个对象,此时事务B想要写入该对象,那么B必须等到A提交或终止才能继续,以确保B不会再事务A执行的过程中去修改对象
                ②如果事务A已经修改了对象,此时事务B想要读取该对象,则B必须等到A提交或终止才能继续,这样才不会出现读到旧值的情况
        说明:两阶段加锁不是两阶段提交
        实现: 1. 读写锁,也就是锁可以处于共享模式或独占模式
                要读取对象,先获取共享锁,要求改对象,需要获取独占锁,可以从共享锁升级到独占锁,事务获得锁之后,一直持有到事务结束,
    
    3. 乐观并发控制技术,例如可串行化的快照隔离

谓词锁: 作用类似于共享/独占锁,而区别在于,它并不属于某个特定的对象(如表的一行),而是作用于满足某些搜索条件的所有查询对象。
        说明: 但是谓词锁的性能不佳:如果活动事务中存在很多锁,那么检查匹配这些锁就变得非常耗时。因此,大多数使用2PL的数据库实际上实现的是索引区间锁(next-key locking),本质上它是对谓词锁的简化或者近似。
                如果没有合适的索引,那么数据会回退到对整个表施加共享锁。


系统容错的复制机制,常见的复制方案:
    1. 主从复制:主节点承担数据写入,从节点在各自节点上维护数据的备份副本。如果从主节点或者同步更新的从节点读取,则可以满足线性化。
    2. 共识算法,共识算法需要解决复制问题,业余要一些措施来防止脑裂和过期的副本。
    3. 多主复制(不可线性化):具有多主节点复制的系统通常无法线性化的,主要由于他们同时在多个节点上执行并发写入,并将数据异步复制到其他节点,因此他们可能会产生冲突的写入。
    4. 无主复制(可能不可线性化): 对于无主节点复制的系统,取决于具体的quorum配置来决定是否保证线性化。


原子提交和两阶段提交:
    原子提交:单节点上,事务提交非常依赖于数据持久写入磁盘的顺序关系:先写入数据,然后在提交记录。事务提交(或终止)的关键点在于磁盘完成日志记录的时刻:在完成日志记录写之前如果发生了崩溃,则事务需要中止;
        如果在日志写入完成之后,即发生崩溃,事务也被安全提交,这就是在单一设备上(某个特定的磁盘连接到一个特定的点)实现原子提交的核心思路。
    两阶段提交:两阶段提交是一种在多接地那之间实现事务原子提交的算法,用来确保所有节点要么全部提交,要么全部中止。她是分布式数据库中的经典算法之一,2PC在某些数据库内部使用,或者以XA事务形势(例如Java Transaction API)
        或SOAP Web服务WS-AtomicTransaction的形式提供给应用程序。
        两阶段提交分为准备阶段和提交阶段,事务开始时,两个事务分别在两个节点上写数据,写数据完成后进入准备阶段,他们告诉协调者准备完成,然后进入提交阶段,所有节点反馈可以提交之后,完成提交。
分布式事务处理:
    1. Exactly-once消息
    2. XA交易: X/Open XA是异构环境下实施两阶段提交的一个工业标准。目前许多传统数关系数据库包括PostGreSQL,Mysql,SqlServer Oracke和消息队列(ActiveMQ,MSMQ,IBM MQ)都支持XA
        XA并不是一个网络协议,而是一个与实物协调者进行通信的C API。当然他也支持其他语言的API绑定,例如JavaEE中,XA事务是由Java事务API来实现。
    分布式事务的限制:
        1. 如果协调者不支持数据复制,而是在单节点上运行,那么他就是整个系统的单节点故障。
        2. 许多服务器端应用程序都倾向于无状态模式,而所有的持久状态都保存在数据库中,这样应用服务器可以轻松地添加或删除实例。但是当协调者就是应用服务器的一部分时,部署方式就发生了根本变化。
            突然间,协调者的日志成为可靠系统的重要组成部分,它要求与数据库本身一样重要,这样应用服务器已经不再是无状态。
        3. 由于XA需要与各种数据系统保持兼容,他最终其实是多系统可兼容的最低标准。例如,无法深入检测不同系统之间的思索条件,不适用于SSI
    

  • 4
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值