zoukankan      html  css  js  c++  java
  • 数据库事务的一致性和原子性浅析

    本文参考自知乎

    Oracle事务的概念:事务用户保证数据的一致性,它是由一组dml语句组成,这组dml语句要么全部执行成功,要么全部执行失败。

    1、事务一致性

    举个例子:假如你去银行转1000元给你的朋友,所有的操作都完成之后,并且提示你转账成功(假设银行是立即转账,不存在延时的情况),你发现你的账户上减少了1000元,但是你打电话给你的朋友确认时,而你的朋友的账户却没有因此增加1000元,那么我们认为这时候的数据就是不一致的状态!!!

    在数据库的实现的应用场景中,一致性可以分为数据库外部的一致性和数据库内部的一致性:

    i、外部的一致性:由外部的应用编码来实现,即银行的应用在进行转账的操作时,必须在同一事务内部调用对账户A和账户B的操作。如果在这个阶段出现错误,这不是数据库本身能解决的,也不属于我们要讨论的范围。

    ii、数据库内部的一致性:在同一个事物内部的一组操作必须全部成功(或者全部失败)。这就是事物处理的原子性

    2、事务原子性

    上面说了事务的原子性是保证:事务内的一组操作全部成功(或者全部失败),为了实现原子性,就需要通过日志:将所有对数据的操作都写入日志,如果事务中的一部分操作已经成功,但后面部分操作,因为系统断电,操作系统崩溃等问题而没有成功执行,那么就要通过回溯日志,将前面已经成功执行的操作撤销,从而达到"全部执行失败"的效果。

    3、体现事务原子性和数据库一致性和持久性的常见场景

    数据库崩溃后重启,此时数据库处于不一致的状态,此时数据库必须做crash recovery操作,大致步骤如下:

    a、通过日志REDO(重演所有执行成功但是未写入到磁盘的操作)

    b、再对到数据库崩溃前没有执行完成的事务进行UNDO(撤销所有执行了一部分,但是有一部份还没有执行完成,且尚未提交的操作,保证事务的原子性)

    c、crash recovery结束后,数据库恢复了一致性,可以继续工作

    4、多线程下的事务存在的问题

    在单线程下,事务的原子性,能保证数据库的一致性,但是在某些情况下,事务的原子性并不能保证数据库的一致性。具体场景如下:

    问题:事务一将100元转到帐号A,那么他先读取帐号A,然后再在帐号A上加上100,但是在这个过程中间,事务二也修改了帐号A,给它加了100元,那么最后的结果应该是加了200元。但是当事务一最终完成后,帐号A只加了100,因为事务二的修改结果被事务一覆盖掉了。

    为了保证数据的一致性,引入隔离性,既保证每一个事务看到的数据是一致的,确保一个事务在处理数据的同时,没有其他事务对自己正在处理的数据进行干扰,就好像其他事务都是不存在的一样,即事务在并发执行后的状态,和串行执行后的状态时一样的,实现隔离性主要通过加锁的方式。

    下面是通过"锁"解决事务在多线程下的数据不一致性问题:

    a、悲观锁

    即事务将当前操作所有涉及到的对象加锁,操作完成后释放给其他对象使用,为了尽可能的提高性能,发明了各种粒度(数据库级/表级/行级)/各种性质(共享锁/排它锁/共享意向锁/共享排它锁/共享排他意向锁......)的锁,想具体了解锁,请参考Oracle锁机制。为了解决死锁问题,又发明了两阶段锁协议/死锁检测等一系列技术

    b、乐观锁

    即不同事务看到通一对象(一般是数据行)的不同历史版本,如果有两个事务同时修改了同一数据行,那么在较晚提交的事务提交使进行冲突检测。实现也有两种:一种是通过UNDO的方式获取数据行的历史版本,另一种是简单的在内存中保存数据行的不同历史版本,通过时间戳来区分

  • 相关阅读:
    http4j
    EmbeddedBrowser
    curl v www.linode.com查看请求及响应信息
    JRUN
    PAC Manager: Ubuntu 上强大的 SSH 帐号管理工具,可取代 SecureCRT
    centos下载地址
    Web应用调试:现在是Weinre和JSConsole,最终会是WebKit的远程调试协议
    用ClusterSSH管理多台Linux服务器(2)
    Ubuntu + IntelliJ + Maven + Jetty + JRebel
    Java的连接池程序
  • 原文地址:https://www.cnblogs.com/GreenLeaves/p/6567507.html
Copyright © 2011-2022 走看看