zoukankan      html  css  js  c++  java
  • SQL 事务与并发

    a) 应用程序事务与数据库存储引擎事务

    b) 应用程序处理并发与数据库存储引擎处理并发

    为什么要从两个方向来考虑呢,是有原因的,首先机制处理方式,以及在软件中的所处的环境以及情节都不同。所以我们可以将事务与并发分为两个部分来讲,这文主要讲MSSQL的事务,我会在接下来的文章谈谈java或者C#处理事务以及结合Martin Fowler说到的并发架构模式探讨。

    什么是事务呢?

    引言:
    假设小强有两张银行卡A和B,卡A内有1000元存款。一天,小强来到银行,打算将卡A中的200元转账到卡B中。当工作人员刚打卡A中的金额减少200元时,银行突然停电了(这种情况并不多见,我们假设银行也没有备用电源)。那么,恢复供电后,小强查询卡A的金额,会出现怎样的情况?

    答案是肯定的,还是1000元。这是因为卡B并没有增加200元。但明明工作人员已经将卡A减少了200元,为何还有1000元呢?这就是事务技术的神奇之处。

    所谓事务指的是一个单元的工作。这个单元中可能包括很多工作步骤,它们要么全做,要么全不做。数据库中执行的操作都是以事务为单元进行的。例如,小强将卡A的钱转到卡B,包括两个步骤:从卡A中减少200元和将卡B增加200元,这就是一个事务。如果只做了第一步,未做第二步,则第一步操作也会被撤销。

    MSDN给出的定义事务是作为单个逻辑工作单元执行的一系列操作。一个逻辑工作单元必须有四个属性,称为原子性一致性隔离性持久性 (ACID) 属性,只有这样才能成为一个事务。

    事务执行模式

    1.自动提交事务(SQL Server默认的事务执行模式)

    2.显示事务(begin transaction,commit,rollback)

    事务以begin transaction 开始,以commit(提交)或rollback(发生故障时,回滚)结束

    例1:假设在选修表中,学号'1002'的学生由于某些原因不选1号课程而改选4号课程,并且该课程的考试成绩为80分。

    如果我们将这两个步骤定义为一个事务的话,代码如下:

    begin transaction
    update 选修
    set 课程号='4'
    where 学号='1002' and 课程号='1'
    go
    update 选修
    set 成绩=80
    where 学号='1002' and 课程号='4'
    commit
    
    select *
    from 选修

    代码运行结果如下:

    例2:但由于编程人员输入错误,把80分误写为‘8o’(为英文字母o)分,导致出错

    begin transaction
    update 选修
    set 课程号='4'
    where 学号='1002' and 课程号='1'
    go
    update 选修
    set 成绩=8o
    where 学号='1002' and 课程号='4'
    rollback

    结果:第一步操作将课程号修改成'4'也没有执行.这正好体现了事务的特性

    工作原理:

    事务确保数据的一致性和可恢复性.事务开始后,事务包含的所有操作都将写到事务日志文件中.这些操作一般有两种,一种是针对数据的操作,另一种是针对任务的操作.针对数据的操作,如插入,删除和修改,这是典型的事务操作,处理的对象是大量的数据.针对任务的操作,如创建索引,这些任务操作在事务日志中记录一个标志,用于表示执行了这种操作.事务恢复的实现技术,包括数据备份,登记日志文件等

     

    什么是并发呢?

    当多个用户同时访问数据时,那么在这种情况下就叫做并发呢。

    引言:

    假设场景如下:

    1)甲和乙两地,同时读取某同一航班的机票剩余数A.

    2)甲地:A=10张,乙地:A=10张

    3)甲售票点卖出一张机票,修改剩余A-1=9,把A写回数据库

    4)同时,乙售票点也卖出一张机票,修改剩余A-1,所以A为9,把A写回数据库

    结果可以看到,明明卖出两张机票,但数据库中机票剩余只减少1

    我们把这种情况称为数据库的不一致性.这种不一致性是由两个事务同时执行操作(即并发操作)引起的.

    并发操作带的数据不一致性包括3类:

    1.丢失修改(上面的场景假设即是)

    2.不可重复读(事务T1读数据后,事务T2执行更新操作,使T1无法再现前一次读取结果)

    3.读"脏"数据(事务T1修改某一数据,并将其写回磁盘,事务T2读取同一数据后,T1由于某种原因被撤销,这时T1已修改过的数据恢复原值,T2读到的数据就与数据库中的数据不一致,则T2读到的数据就为”脏”)

    实现并发控制的重要技术

    封锁的基本原理

    锁定

    每个事务对所依赖的资源(如行、页或表)请求不同类型的锁。锁可以阻止其他事务以某种可能会导致事务请求锁出错的方式修改资源。当事务不再依赖锁定的资源时,它将释放锁。

    行版本控制

    当启用了基于行版本控制的隔离级别时,数据库引擎 将维护修改的每一行的版本。应用程序可以指定事务使用行版本查看事务或查询开始时存在的数据,而不是使用锁保护所有读取。通过使用行版本控制,读取操作阻止其他事务的可能性将大大降低。

    丢失更新

    当两个或多个事务选择同一行,然后基于最初选定的值更新该行时,会发生丢失更新问题。每个事务都不知道其他事务的存在。最后的更新将覆盖由其他事务所做的更新,这将导致数据丢失。
    例如:
    两个编辑人员制作了同一文档的电子副本。每个编辑人员独立地更改其副本,然后保存更改后的副本,这样就覆盖了原始文档。最后保存其更改副本的编辑人员覆盖另一个编辑人员所做的更改。如果在一个编辑人员完成并提交事务之前,另一个编辑人员不能访问同一文件,则可避免此问题。   很显然的,如果你和你同事同时修改一个代码,当你们都搞定准备提交的时候,那么可怕的事情就发生了,因为晚提交的往往才胜利,他将会覆盖你的版本,意味着你白忙活了。同样的,可以把这种事情隐射到许多情况之下。

    未提交读(脏读)(Example 1)

    当第二个事务选择其他事务正在更新的行时,会发生未提交的依赖关系问题。第二个事务正在读取的数据还没有提交并且可能由更新此行的事务所更改。
    例如:
    一个编辑人员正在更改电子文档。在更改过程中,另一个编辑人员复制了该文档(该副本包含到目前为止所做的全部更改)并将其分发给预期的用户。此后,第一个编辑人员认为目前所做的更改是错误的,于是删除了所做的编辑并保存了文档。分发给用户的文档包含不再存在的编辑内容,并且这些编辑内容应视为从未存在过。如果在第一个编辑人员保存最终更改并提交事务之前,任何人都不能读取更改的文档,则可以避免此问题。

    清清软件园 http://sillysoft.taobao.com
  • 相关阅读:
    数据结构与算法(二)(栈、队列)
    数据结构与算法(一)(数组、线性查找、二分查找)
    ssm项目中常用的上传文件
    安全防御之防xss、SQL注入、与CSRF攻击
    int i=i++;和i=++i;和i++
    关于@Autowired和@Resource注解区别
    通过idea创建Maven项目整合Spring+spring mvc+mybatis
    深入理解java虚拟机(一)
    java中栈,堆,方法区
    SpringBoot+mybatis配置pagehelper实现基础分页
  • 原文地址:https://www.cnblogs.com/lqsilly/p/3056044.html
Copyright © 2011-2022 走看看