关闭

数据库的事务

标签: 数据库
105人阅读 评论(0) 收藏 举报

1.事务

我们常说的事务就是让一个事务内包含的所有sql要么是全部执行,要么全部失败。

2.特性

原子性和隔离性

原子性:事务中的操作要么都做,要么都不做。

隔离性:一个事务的执行不能被其他的事务所干扰(涉及事务的并发执行)

3.并发

我们平时说的丢失修改、脏读、不可重复读、幻读等都是因为事务之间的并发执行所带来的结果,也就是没有保持事务的隔离性

并发导致的四种情况:

丢失修改:事务T1 读取A=10,事务T2同时也读取A=10,这时事务T1修改了A=A-1 写回了A=9,而事务T2也修改了A=A-4 写回了A=6,覆盖了T1对A值得修改,导致了事务T1修改的丢失。

脏读:事务T1读取B=100,对B进行了修改B=B*2=200,写回了B=200。事务T2读取了B=200,这时,事务T1由于某种原因撤销了操作,B恢复了100。导致了事务T2读入了T1的脏数据。

不可重复读:事务T1读取A=50,B=100,A+B=150,。事务T2读取B=B*2=200,写回了B=200。这时T1在读取A=50,B=200,求和是250,。导致和之前的统计值不一致,造成了不可重复读。

幻读:其实属于不可重复读的范畴。事务T1按一定条件从数据库中读取了某些数据记录后,事务T2删除了部分记录或者添加记录,那么当T1再次按相同条件读取数据时,发现其中莫名其妙的少了或者多了一些记录。这些数据对于T1来说就是幻影,所以称为幻读。


那么怎么控制并发呢?

数据库像java线程解决并发带来的安全问题一样也提供了锁的机制。基本的锁类型有两种:即共享锁(也称为S锁或者读锁)和排它锁(也称为X锁或写锁)


共享锁:若事务T给数据对象A加上S锁,则事务T可以读A,不能修改A,其他的事务只能给A加S锁,不可加X锁,直到释放了A上的S锁为止。

排他锁:若事务T给数据对象加上了X锁,则允许T读取和需要A,但是不允许其他的事务再给A加上任何类型的锁进行任何操作。即一旦一个事务获得了某一数据的排它锁,其他事务均不能对数据进行排他封锁,其他事务只能进入等待状态,直到第一个事务撤销了对该数据的封锁。


那怎么样运用这两种锁呢?需要约定了一些规则来运用这两种锁,这就是封锁协议。

一级封锁协议:用来解决并发带来的丢失修改问题。对事务T要修改的数据加上X锁,直到事务结束时(包括正常结束和非正常结束)才释放。但是如果事务T只是读数据而不对其进行修改,则不需要加锁,因此,不能保证脏读和不可重复读。

二级封锁协议:用来解决并发带来的脏读问题。一级封锁协议加上事务T对要读取的数据加S锁,读完后即释放S锁。用于事务T读取完数据就释放S锁,所以不能解决不可重复读的问题。

三级封锁协议:用来解决不可重复读的问题。以及协议加上事务T对要读取的数据加S锁,并直到事务结束才释放。


我们平时在spring的Aop里面可以指定这几种五种隔离级别

Isolation属性一共支持五种事务设置,具体介绍如下:

 ① DEFAULT 使用数据库设置的隔离级别( 默认 ) ,由 DBA 默认的设置来决定隔离级别.

 ② READ_UNCOMMITTED 会出现脏读、不可重复读、幻读( 隔离级别最低,并发性能高 )

 ③ READ_COMMITTED  会出现不可重复读、幻读问题(锁定正在读取的行)

 ④ REPEATABLE_READ 会出幻读(锁定所读取的所有行)

 ⑤ SERIALIZABLE 保证所有的情况不会发生(锁表)


死锁:如果事务T1封锁了数据R1,T2封锁了数据R2,然后T1又请求了封锁R2,由于T2已经封锁了R2,因此T1只能等待T2释放R2的锁。然后T2又请求封锁R1,由于T1已经封锁了R1,因此T2也只能等待T1释放R1的锁。此时T1和T2都在等待对方先释放锁,因此形成死锁。


解决死锁目前有两种方法:

一次封锁法:就是每个事物一次将所要使用的数据全部加锁,这样就不能出现,互相访问加锁数据的问题了。

顺序封锁法:预先对数据对象规定一个顺序,所有事务都按照这个顺序封锁。


并发调度可串行性:

计算机系统对于并发事务中的操作的调度是随机的,而不同的调度会产生不同的结果,那么哪个结果是正确的,哪个是不正确的?如果对个事务再某一调度下的执行结果与这些事务在某个串行调度下的执行结果相同,那么这个调度就是正确的。

事务T1:读B;A=B+1;写回A;

事务T2:读A;B=A+1;写回B;

A和B的初始值都是4,如果按照先T1后T2的顺序,A=5,B=6;如果按照先T2后T1的顺序,B=5,A=6。当执行并发调度时,如果结果是这两个的其中一个,则认为结果是正确的。


两端锁协议

保证了并发调度的可串行性的封锁协议

具体内容包括:

1.在对任何数据进行读、写之前,首先事务要获取对该(所有用到的)数据的封锁。

2.在释放一个封锁之后,事务不再申请和获取任何其他的封锁。


 








0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:388次
    • 积分:41
    • 等级:
    • 排名:千里之外
    • 原创:4篇
    • 转载:0篇
    • 译文:0篇
    • 评论:0条
    文章分类
    文章存档