设为首页 收藏本站
查看: 801|回复: 0

[经验分享] SQL SERVER之事务

[复制链接]
累计签到:1 天
连续签到:1 天
发表于 2014-5-23 09:50:40 | 显示全部楼层 |阅读模式
  在实际对数据库的使用中,会出现多个用户同时对某一张表进行操作,当多个用户在同一时间对同一张数据表进行读取或者修改操作时,若处理不当就有可能发生冲突问题。为了解决这样的问题,就需要使用事务的控制和管理机制。


事务

   单个逻辑工作单元执行操作的集合,也可以看作是多条语句封装的结果。通过事务可以保证数据表中数据的一致性。
事务的特性




原子性

   是指事务中所有的执行操作,要么全部成功,要么不执行。如在商场购物中,管理员同时对用户进行充值操作。

    修改账户A中的现金数。

    修改账户A中的现金数

    如果在执行第一个SQL语句之后,第二个语句之前,突然断电了该如何办?

     

一致性

所谓的事务的一致性,是指一个事务操作执行完周,数据库中的数据必须处于合法一致的状态。例如如果账户A给账户B转账1000元后,那么账户A应该减少1000,账户B应该增加1000,但是两人的钱数总和还是一致的,应该处于合法的状态中。

隔离性

    就是事务看到的数据库中的数据要么是这个事务被修改之前的状态,要么是被修改之后的状态。



持久性

   如果一个事务被成功地修改,其结果在数据库中不会因为软件,硬件等故障而改变,数据会永久的保留下来




控制事务的流程

START TRANSACTION(开始事务)、COMMIT(提交)、ROLLBACK(事务回滚)


显示开始一个事务



使用START TRANSACTION或者BEGIN语句可以显示开始一个新的事务



语法规则:

START TRANSACTION{事务名}

     
隐式开始一个事务



在SQL语句中的第一条语句开始就表示隐式开始了一个新的事务


提交事务



显示提交:COMMIT[事务名]



    start transaction   --开始事务  
    insert into accounttable values('A',5000)  
    update accounttable set cashvalue=cashvalue+1000  
    where accountuser ='A'  
    commit   --提交事务  


(这里把两条语句封装到了一起,一个是插入语句,一个是更新语句)


隐式提交



是指通过使用SQL语句就可以完成事务的提交,如果执行了CREATE TABLE,DROP TABLE等



操作就会自动提交事务。




自动提交

自动提交指通过设置AUTOCOMMIT命令完成事务的提交。



自动提交语句

SET AUTOCOMMIT=1

SET AUTOCOMMIT ON



关闭自动提交方式

SET AUTOCOMMIT=0

SET AUTOCOMMIT OFF




回滚事务

  是表示当事务执行失败时,数据库恢复到该事务操作之前的那一个合法状态中,并撤销对该表的一些操作。同时在数据库中还可以设置保存点,可以当发生意外时,回滚到保存点状态。



    begin try  
    begin transaction  
    --使用try语句进行捕捉错误  
      
    insert into accounttable values(5000,'A')  
    save tran a1  
    insert into accounttable values(5000,'C')  
    commit  
    end try  
      
    begin catch  
    --当发生错误时,进行回滚  
    rollback tran a1  
    end catch  




(这段SQL语句,分别设置了2个保存点,分别是A1,A2,并使用rollback回滚机制)



并发事务的工作流程

    用户user1使用SELECT语句查询到accounttable账户中有5000元,但是由于某些原因,用户user1并没有提取现金

    用户2也通过SELECT语句查询到accounttable账户中有5000元,此时他开始事务,从账户中提取出了1000元,但是并没有提交事务。此时用户user1查到的还是5000元

    在用户user1查询到账户余额为5000后,希望全部提取出来,但是由于user2的事务并没有提交,所以用户1并不能提取

    用户2提取1000后,提交了事务,此时剩余4000元

    用户1终于可以执行提取5000元操作了,可是此时只有4000元,操作将被撤销,回滚到他之前的操作状态

    如果用户1还想全部取出的话,就必须开始一个新的事务

     

通过以上的叙述我们发现事物并发处理中存在的问题



    读脏数据

    是指那些已经更改但还是没有被提交的数据。如用户2取走1000后,用户1提取5000时,会发现账户的余额不足。

    不能重复读

    同一个事物中在多次执行时,由于其他事务对其做的修改或者删除等更新操作时,使得每次查询时返回的数据结果都不相同。如上例中,用户2已经取出1000元,而用户1查询到的仍然是5000元

     

     

    幻想读

    是指读取了其他事务中执行完插入或者更新操作后的错误数据。

     

    ------------------------------------------------------------------------




事务的隔离级别

1.READUNCOMMITTED:未提交读。正如上面叙述的那样,由于用户2没有提交,所以用户1还是读出了5000元。在READ UNCOMMITED隔离级别下,会隔离UPDATE语句,但不隔离SELECT语句。它的隔离级别最低。





2.READ COMMITTED:提交读。给隔离级别在读取数据时对其加共享锁,可以避免读脏数据,但是在READ COMMITTED隔离级别下,事务在结束前更改可以更改数据,因此不能避免不能重复读或者幻想读。



3.REPEATABLE READ:可重复读。在该隔离级别中会将查询中使用的所有数据锁定,防止其他用户对改数据进行操作,可以避免产生不能重复读。

4.SERIALLZABLE :可串行化。该隔离级别在事务提交之前,会锁定整个数据表,防止其他用户对数据进行增加、删除和修改等更新操作。



下面是有关四种隔离级别允许不同的类型的行为


隔离级别
脏读
不可重复读取
幻象
未提交读
提交读
可重复读
可串行读


牛刀小试
下面的例子均以下表为例
                                     Table
Money
Int
Name
Char(4)



脏读操作
由上面的表格可知,脏读操作发生在未提交数据时,正如我们的例子中,用户1查到了5000的情况。如下操作
第一个连接语句
    <span style="font-family:SimSun;font-size:18px;">begin tran  
    update table set money=103 where name='A'  
    waitfor delay '00:00:10' --等待10秒  
      
    update table set money=104 where name='A'  
    commit tran</span>  


接着马上执行第二个连接语句


    <span style="font-family:SimSun;font-size:18px;">set transaction isolation level read uncommitted  
    begin tran  
    select money from table where name='A'  
    commit tran</span>  


最终结果是103,而不是104,这就是脏数据,可知如果我们把第二个连接中的事务隔离级别设置为 READ MOMMITED、REPEATABLE READ或者SERIALLZABLE就可以避免这种情况发生。


非重复读操作

第一个连接语句



    <span style="font-family:SimSun;font-size:18px;">set transaction isolation level read committed  
    --或者是set transaction isolation level read uncommitted  
      
    begin tran  
    select money from table where name='A'  
    waitfor delay '00:00:10'  --等待10秒  
    select money from table where name='A'  
    commit tran  
    </span>  


接着马上执行第二个连接语句




    <span style="font-family:SimSun;font-size:18px;">begin tran  
    update table set money=10 where name='A'  
    commit tran</span>  


我们发现第一个连接中两次返回账号的余额不一样,第一次是100,第二次是10,这就是典型的“非重复读”的问题

根据上表所示,如果把事务的隔离级别设置为REPEATABLE READ或者SERIALLZABLE可以防止此类问题


幻象读

根据上表所示,当事务的隔离级别为READ COMMITTED、READ UNCOMMITTED、REPEATABLE READ时就会发生幻象



先看下面的例子(账户余额为100)

第一个连接语句



    <span style="font-family:SimSun;font-size:18px;">begin tran  
    select * from table  
    waitfor delay '00:00:10'--等待10秒  
    select * from table  
    commit tran</span>  


接着马上执行第二个连接语句




    <span style="font-family:SimSun;font-size:18px;">begin tran  
    insert into table values(300,'a')  
    commit tran</span>  


我们发现两次查询的结果不一样,这就是典型的”幻象读”问题,可知解决方法为把隔离级别设置为SERIALLZABLE即可。





小结:在实际应用的时候,采用何种隔离级别应视具体情况而定。


运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-19545-1-1.html 上篇帖子: SQL SERVER中的视图 下篇帖子: SQL面试题
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表