1. 理解事务
- 当我们把多个操作打包成一个整体后,这就可以称为一个事务。
为什么需要将多个操作打包成一个整体?
举个例子: 转账
路人甲要将账户里的1000元钱通过网上银行转账到路人乙的账户上。这时就可以分成两个操作:
- 操作1 : 先从 路人甲 的账户上扣除 1000 元。
- 操作2 : 再将 路人乙 的账户上增加 1000 元。
注意 :只有当上述的两个操作都执行成功后,才能说转账成功!!!
分析一下上述的问题,我们发现对于 路人甲 和 路人乙 来说,我们只需要两种状态:
- 操作1 和 操作2 都执行成功。(从用户的视角出发就是转账成功!)
- 操作1 和 操作2 一个都不执行。(从用户的视角出发就是转账失败!)
所以为了避免出现只有一个操作被执行了的情况。我们就需要将这两个操作给打包成一个整体 — 事务
事务的两种状态怎么进行判断?
打包成为事务后,从我们的角度看是只有两种状态的(都执行成功,一个都不执行)。
但是第二种状态:一个都不执行 是怎么去进行判断和处理的???
原来在执行每个事务时,操作都会被依次执行,如果操作全都执行成功,这时就是 第一个状态:事务执行成功。(最后使用 commit 来表示该事务执行成功!)
而如果只有其中的部分操作执行成功了,还有部分操作执行失败了,那么这时就是 第二个状态 : 事务执行失败。(这时就可以使用 回滚(rollback),就相当于进行逆操作,将数据恢复成该事务执行前的状态,这时从我们的视角看来就是 事务的操作一个都没执行)
事务的具体使用?
-
- 开启事务:start transaction;
-
- 执行多条SQL语句
-
- 回滚或提交:rollback / commit;
注意:rollback即是全部失败,commit即是全部成功。
示例(回滚)
示例(commit)
2. 事务的四个基本特性
1. 原子性
这个特性就是上面所说的打包,使多个操作成为一个整体。打包而成的事务只会有两个状态:执行成功(事务中所有的操作都执行成功);执行失败(事务中的所有的操作一个都没执行)。
总结:就是不可再分割的操作。
2. 一致性
这个特性表示,一个事务在执行之前或执行之后,数据库里的数据必须是合理且合法的。
比如: 转账。
转账前和转账后,账户上的钱都不可能是负数。
3. 持久性
当一个事务提交(commit)之后,那么被操作后的数据就必须是持久化的存储在了硬盘上。而不是临时存储的。
4. 隔离性(较为复杂)
总的来说 隔离性 就是描述 事务 在并发执行时,发生的情况!!!(主要是多个事务同时操作同一份数据)
-
脏读
-
举个栗子,我这时正在写一篇文章,突然来了一个人,他偷偷瞄了下我的屏幕。然后他看到了文章中所列举的一个例子。他记了下来。后来当我写完这篇文章后,我发现文章中举的例子不合适,所以我就把这个例子给删了,换了一个。这时中途瞄我屏幕的人所拿到的例子和我文章中的例子就不相同 — 这就是脏读问题。
-
总结:脏读就是一个事务在执行的过程中,另一个事务读取了前一个事务还没有提交的数据,从而不能保证所读取的就是最终结果。
-
-
不可重复读
-
还是上面的例子,我们为了解决脏读问题,所以我们给写操作加锁。这样一来就变成了,我正在写文章,并且不允许其他人来看,直到我提交为止。而那些提前来的人只能等我提交完毕,然后开始读操作。然而这时又有了一个问题,其他人开始读的时候,我又可以进行写操作,这样就导致了一个问题,那就是其他人进行多次读的时候发现前后两次读出的数据不一致。— 不可重复读问题。
-
总结:不可重复读就是一个事务在进行读操作的过程中,另一个事务又开始进行写操作,从而使读操作中多次读取的数据不一致。
-
-
幻读
- 接着上面的例子,我们就需要把不可重复读的问题给解决掉。通过上面的分析我们发现,问题的出现就是因为读操作时没有进行隔离,使写操作可以执行。所以我们就把读操作也给加上锁。这时就变成了读写操作都有锁的情况。就能把不可重复读的问题给解决了。 但是进行仔细分析后,发现还是会有一个问题:那就是虽然我们已经给读操作和写操作上锁了,但我们是给同一张表中的某几行数据进行上锁的。所以当在进行读操作的时候,写操作可以对其他的行进行操作。这时就会导致一个问题,那就是会使读操作在前后两次读取数据时多几行或者少几行。— 幻读问题。
- 总结:幻读就是一个事务中进行前后两次读取数据时,发现前后读取数据的集合不同。(多了或者少了)
-
串行化
- 由于在上面的例子中出现了 幻读 问题,所以为了解决这种问题,我们只能使用 串行化 执行方式。
- 串行化:就是一个事务在进行读操作时,另一个事务只能等待。也就是事务依次执行。
- 总结:串行化就是使事务依次执行,虽然解决了上述的 脏读 、不可重复读 和 幻读 问题,但它的隔离性太高,并发性太低,数据虽然可靠,但是速度最慢。
通过对隔离性的分析,我们发现事务的并发性和隔离性是不可兼得的。注重并发,势必降低隔离性,反之也是如此。所以我们就可以通过不同的隔离级别来控制隔离性和并发性。
-
read uncommitted
允许读取未提交的数据,隔离性最低,并发性最高。会有 脏读、不可重复读、幻读 问题。
-
read committed
只允许读取提交之后的数据,隔离性提高,并发性降低。会有 不可重复读、幻读 问题。
-
repeatable read
相当于读和写操作都加锁,隔离性大大提高,并发性大大降低。会有 幻读 问题。
-
serializable
串行化执行,隔离性最高,并发性最低。解决了 脏读、不可重复读、幻读 问题,但速度最慢。