mosh数据库——第十一章

1.事务

  • 事务是代表单个工作单元一组SQL语句,所有这些语句都应成功完成,否则事务会运行失败。
  • 我们在需要对数据库进行多次更改的情况下使用事务,并且我们希望所有这些更改作为一个单元一起成功或失败。

事务的属性ACID):

  1. 原子性|Atomicity(事务就像原子一样,它们牢不可破。)                                                  每个事务都是一个工作单元,不管它包合多少语句,要么所有这些语句都成功执行且事务被提交,要么事务被退回去所有更改被撤销。
  2. 一致性|Consistency                                                                                                              这意味着通过使用事务,数据库将始终保持一致的状态,不会出现有订单没有项目的情况)
  3. 隔离性质|Isolation                                                                                                                    这些事务相互隔离,或者当有同样的数据被更改时各自受到保护,所以他们不会相互干扰如果多个事务想更新相同的数据,受影响的行就会相互锁定,因此一次只有一个事务可以更新行,其他事务必须等那个事务完成。
  4. 持久性|Durability                                                                                                                      一旦事务被提交,事务产生的更改是永久的。所以如果你停电或者系统崩溃,我们也不会丢失更改内容。

2.创建事务

START TRANSACTION语句:创建事务

USE sql_store;
START TRANSACTION;

在这个事务, 首先要将订单插入订单表

INSERT INTO orders (customer_id, order_date, status)
VALUES (1, '2019-01-01', 1)

接下来,我们要插入订单项目

INSERT INTO order_items
VALUES (LAST_INSERT_ID(),1,1,1);  -- LAST_INSERT_ID()这会返回最新插入订单的id

最后,需要使用COMMIT语句关闭事务。当MySQL看到这个指令,它会把所有的更改都写入数据库。如果其中一个更改失败,它会自动撤消之前的更改(我们说这样的事务就是被退回了)。

COMMIT;

第二个插入语句失败(可能是客户端崩溃、网络脱机或服务器崩溃)的话,我们的事务会被退回,并且第一个语句,做的更改会自动取消

逐行查询脚本语句(查询窗口之下的快捷键),模拟第二个语句插入失败

但在某些情况下,我们可能想进行一些错误检查,并手动退回了事务,

这种情况下,我们使用ROLLBACK语句,而不是commit语句 

MySQL会装好我们写在事务里的每一条语句,然后如果语句没有返回错误,它就会提交。所以每当我们有INSERT、UPDATE或DELETE语句时,MySQL会先把它们装在事务里,然后自动提交。它由一个叫做自动提交的系统管控(被默认设置为开:所以每当我们执行一条语句,MySQL将该语句放进事务中,如果语句没有引发错误就提交)

3.并发和锁定

当一个用户修改其他用户正在检索或修改的数据时,并发可能会成为一个问题。本节课你们会学习,在默认情况下MySQL怎么处理并发问题。

我们要模拟两位用户试图同时更新给定顾客的积分的情况:

先回到MY SQL工作台主页,新建一个服务器连接,现在我们有两个独立的连接或会话

MYSQL放了一个锁到我们更新的顾客行上,如果另一个事务尝试更新同一行,它必须等到第一个事务完成(要么提交,要么返回,这就是为什么这里有这个旋转指针)

所以如果一个事务试图修改一行或多行,它给这些行上了锁,这个锁防止其他事务修改这些行
直到第一个事务完成,被提交或者被退回

所以,MY SQL默认状态下的锁定行为,多数时候你不必担心并发问题。

但在某些特殊情况下,默认行为不足以满足你应用里的特定场景,在这种情况下你可以改写默认行为。

4.并发问题

并发的常见问题:

丢失更新|Lost Updates :当两个事务尝试更新相同的数据并且没有上锁时,就会发生这种情况。

在这种情况下,较晚提交的事务会覆盖较早事务做的更改。解决方法:使用锁(会一个接一个进行)。

脏读|Dirty Reads:脏读就是当一个事务读取了尚未被提交的数据

为了解决这个问题,我们需要为事务建立隔离级别。这样事务修改的数据不会立马被其他事务读取,除非它提交了COMMIT

标准的SQL定义了4个事务隔离级别,其中一个就是“读已提交”。当我们对事务使用这个隔离级别时,那个事务只能读取已提交的数据,这样就避免了脏读。

不可重复读|Non-repeating Reads:当我们在事务中添加更多隔离时,我们可以保证事务只能读取已提交的数据。但如果在事务过程中,你读取了某个数据两次,并得到了不同的结果怎么办。

需要增加事务隔离级别:我们要将它与其他事务隔离,确保数据更改对事务不可见

SQL标准定义了另一个隔离级别,叫做“可重复读”。这个级别上,我们读取的数据是可重复和一致的。就算有其他事务更改了数据,我们会看到首次读取就创建的快照

幻读|Phantom(幽灵)Reads:这种突然出现的数据,就像幽灵一样,我们无法在查询中看到它们,因为它们是在执行查询后才添加、更新或删除的。

如果把所有符合条件的客户都包括在我们的事务中是至关重要的,我们就必须确保没有任何其他事务正在运行,并会影响我们用以查找符合条件客户的查询。

我们有另一个隔离级别称为“序列化”,它能保证当有别的事务在更新数据时,我们的事务能够知晓变动。如果有其他事务修改了可能影响查询结果的数据,我们的事务必须等它们完成

        这样事务就会按序列化执行,这是我们可以应用于一个事务的最高隔离级别,它为我们的操作提供了最大的确定性,但它是有代价的。我们拥有的用户和并发事务越多,我们就要等越久,我们的系统也会越慢。

        所以隔离级别会损害性能和可扩展性,出于这个原因,我们应该只在真的有必要防止幻读的情况下才保留此项

5.事务隔离级别

“读未提交”基本无法解决这些问题中的任何一个,因为我们的事务没有彼此隔离,它们可以读取彼此未提交的更改。

“读已提交”,给予了我们的事务一定的隔离,这样我们只能读取已提交的数据,防止了脏读。 但是这一级别下,很可能在事务中会读取同个内容两遍并得到不同的结果,因为另外一个事务在两次读取之间更新了数据。所以它无法保护我们不进行不可重复读,就是这样我们才需要“可重复读取”级别。

“可重复读取”级别下,我们可以确信不同的读取会返回同样的结果,即使数据在这期间有作更改。

“可序化”,可以阻止以上常见的问题。这一级别可以防止幻读,所以要是数据在期间变动了,我们的事务会待定,以获取最新数据,显然这会给服务器加重负担,因为它在存储和CPU方面都需要额外资源,用以管理需要等待的事务。

所以隔离级别越高,会存在越重的性能和可扩展性问题,因为它会需要用到更多隔离事务的锁。

概括一下,更低的隔离级别会更容易并发,会有更多用户可以在同时接触到同一数据,但更多并发问题也意味着更多并发问题。反过来说,有着更高的性能,因为我们需要用以隔离事务的锁也更少了。

较高的隔离级别限制了并发,意味着更少的并发问题,但是会以降级性能和可拓展性为代价。因为我们会有更多的锁和资源。

因此,最快的隔离级别是读为提交,因为它不设置任何锁,并且忽略了其他事务设置的锁,出于这个原因,我们可能会遇到所有的并发问题。这个列表约往下,可以更好地防止并发问题,意味着我们要使用更多的锁(而且这需要更多的资源,可能会损害性能和可扩展性)。

在MySQL中,默认的事务隔离级别是“可重复读取”,这在大多数场景下都很好使,它比可序化更快,并且防止了除幻读外的大多数并发问题,所以我们可以优先选择这个级别


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值