【笔记】SQL 6

本文介绍了MySQL的事务控制语句,包括COMMIT、ROLLBACK和BEGIN,以及锁的概念、重要性和不同类型的锁,如自增锁、共享锁和排它锁。通过案例展示了事务在数据库并发控制中的作用,强调了锁在保证数据一致性和并发访问安全性中的关键角色,同时也指出锁带来的额外开销。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

MySQL 事务语句

MySQL 为我们提供了以下重要语句来控制事务:

  • 为了启动一个事务,你使用 START TRANSACTION 语句。BEGIN 或 BEGIN WORK 是 START TRANSACTION 的别名。
  • 要提交当前事务并使其变化永久化,你要使用 COMMIT 语句。
  • 要回滚当前事务并取消其变化,你可以使用 ROLLBACK 语句。
  • 要禁用或启用当前事务的自动提交模式,你可以使用 SET autocommit 语句。
  • 默认情况下,MySQL 自动将更改永久性地提交给数据库。要强迫 MySQL 不自动提交更改,你可以使用以下语句:
  • SET autocommit = 0;
    
    -- OR --
    
    SET autocommit = OFF

你使用下面的语句来明确地启用自动提交模式:

SET autocommit = 1;

-- OR --

SET autocommit = ON;

COMMIT 实例

为了使用事务,你首先要把 SQL 语句分成逻辑部分,并确定数据何时应提交或回滚。
下面说明了创建一个新的销售订单的步骤:

  • 首先,通过使用 START TRANSACTION 语句启动一个事务。
  • 接下来,从 orders 表中选择最新的销售订单号,并使用下一个销售订单号作为新的销售订单号。
  • 然后,在 orders 表中插入一个新的销售订单。
  • 之后,在 orderdetails 表中插入销售订单项目。
  • 最后,使用 COMMIT 语句提交该事务。

你可以选择从 orders 和 orderdetails 表中选择数据来检查新的销售订单。

-- 1. start a new transaction
START TRANSACTION;

-- 2. Get the latest order number
SELECT 
    @orderNumber:=MAX(orderNUmber)+1
FROM
    orders;

-- 3. insert a new order for customer 145
INSERT INTO orders(orderNumber,
                   orderDate,
                   requiredDate,
                   shippedDate,
                   status,
                   customerNumber)
VALUES(@orderNumber,
       '2005-05-31',
       '2005-06-10',
       '2005-06-11',
       'In Process',
        145);
        
-- 4. Insert order line items
INSERT INTO orderdetails(orderNumber,
                         productCode,
                         quantityOrdered,
                         priceEach,
                         orderLineNumber)
VALUES(@orderNumber,'S18_1749', 30, '136', 1),
      (@orderNumber,'S18_2248', 50, '55.09', 2); 
      
-- 5. commit changes    
COMMIT;

ROLLBACK 实例

首先,登录到 MySQL 数据库服务器,从 orders 表中删除数据:


mysql> START TRANSACTION;
Query OK, 0 rows affected (0.00 sec)

mysql> DELETE FROM orders;
Query OK, 327 rows affected (0.03 sec)

正如你从输出中看到的,MySQL 确认 orders 表中的所有行被删除了。

第二,在一个单独的会话中登录到 MySQL 数据库服务器,查询 orders 表中的数据:

在这第二个会话中,我们仍然可以看到 orders 表中的数据。

我们已经在第一个会话中进行了修改。然而,这些变化并不是永久性的。在第一个会话中,我们可以提交或回滚这些变化。

出于演示的目的,我们将回滚第一个会话中的更改。

mysql> ROLLBACK;

 在第一次会话中,我们还将验证 orders 表的内容:

 我们要向 teachers 表中插入一条 Xie Xun 的信息,其年龄为 49 岁,国籍为 CN,请补充 SQL 语句,来实现插入 Xie Xun 的信息。

-- 不要删除预置代码 --

-- 开启一个事务 -- 

BEGIN;

-- 插入 Kansas 的信息 --

-- Write your SQL Query here --

insert into teachers (name, age, country) values ('Xie Xun', 49, 'CN');

COMMIT;

向 teachers 表中插入一条 Kansas 的信息,其年龄为 41 岁,国籍为 UK,请补充 SQL 语句,来实现插入 Kansas 的信息。

BEGIN;

insert into teachers (name, age, country) values ('Kansas', 41, 'UK');

COMMIT;

锁的认识

锁的解释

锁:计算机协调多个进程或线程并发访问某一资源的机制。

锁的重要性

在数据库中,除了传统的计算资源(CPU、RAM、I\O等)的争抢,数据也是一种供多用户共享的资源。

因此,如何保证数据并发访问的一致性,有效性,是所有数据库必须要解决的问题。
锁冲突也是影响数据库并发访问性能的一个重要因素,因此锁对数据库尤其重要。

锁的缺点

加锁是消耗资源的,锁的各种操作,包括:获得锁、检测锁是否已经解除、释放锁等,都会增加系统的开销。

请编写 SQL 语句,查看你当前使用的数据库是什么事务隔离级别

SHOW VARIABLES like '%isolation%';

查看你当前使用的数据库是什么事务隔离级别

show variables like '%isolation%'; 

InnoDB 锁的种类之自增锁

自增锁(Auto-inc Locks; table-level lock)

查询当前数据库的自增锁模式:

show variables like '%innodb_autoinc_lock_mode%';
  • 0traditonal 每次 insert 语句执行都会产生表锁

  • 1consecutive simple insert 会获得批量的锁,保证一批插入自增序列的连续性,插入之前提前释放锁,在这个模式下你会发现当你 insert 多条数据回滚的时候虽然 DB 没有插入数据,但是自增 ID 已经增长了,也是数据库默认的级别

  • 2interleaved 不会锁表,实时插入,并发最高,但是基于主从的复制是不安全的,感兴趣可以去查询 RBR 和 SBR 的优缺点

通过查询知道,我们的数据库是开启 consecutive 级别,simple insert 表示通过分析 insert 语句可以确定插入的数量;如:insert, insert, insert … valies(), values(), values();相应的其他插入方式还有 Bulk inserts,Mixed-mode inserts 等。
官方原话如下

An AUTO-INC lock is a special table-level lock taken by transactions inserting into tables with AUTO_INCREMENT columns. In the simplest case, if one transaction is inserting values into the table, any other transactions must wait to do their own inserts into that table, so that rows inserted by the first transaction receive consecutive primary key values.

 自增锁是一种特殊的表级别锁(table-level lock),专门针对事务插入 AUTO_INCREMENT 类型的列。最简单的情况,如果一个事务正在往表中插入记录,所有其他事务的插入必须等待,以便第一个事务插入的行,是连续的主键值。

案例

如果没有自增锁的情况下如下表,id 为自增 AUTO_INCREMENT = 4

这时开启一个事务 A:insert 一条记录张三丰,自增序列分配到的 id 为 4,事务不提交

又开启一个事务 B:insert 一条记录张翠山,自增序列分配到的 id 为 5,事务不提交

事务 A 又插入一条记录,insert 一条记录为殷梨亭,这个是后被分配到的 id 为 6

由于在读提交事务隔离级别下不会查询到其他未提交的事务, 事务 A 此时查询 id>3 的记录会返回 4:张三丰,6:殷梨亭。就会有一个事务里提交的数据自增 id 不是连续的问题产生

此时自增锁就会帮助搞定这个问题

  • innodb_autoinc_lock_mode = 0

在这一模式下,所有的 insert 语句都要在语句开始的时候得到一个表级的 auto_inc 锁,在语句结束的时候才释放

这种模式下 auto_inc 锁一直要保持到语句的结束,所以这个就影响到了并发的插入
但是主从同步时候是安全的

  • innodb_autoinc_lock_mode = 1

这一模式下去 simple insert 做了优化,由于 simple insert 一次性插入值的个数可以立马得到确定,所以 MySQL 可以一次生成几个连续的值,用于这个 insert 语句,也保证主从同步基于语句的复制安全

这一模式也是 MySQL 的默认模式,这个模式的好处是 auto_inc 锁不要一直保持到语句的结束,只要语句得到了相应的值后就可以提前释放锁

  • innodb_autoinc_lock_mode = 2

无自增锁,会导致上面案例的问题,同一批 insert 提交自增不连续

查看 MySQL 数据库的自增锁模式

show variables like '%innodb_autoinc_lock_mode%';

InnoDB 锁的种类之共享锁和排他锁

共享锁和排它锁(Shared and Exclusive Locks)

并发控制

提到共享锁和排它锁就不得不提并发控制(Concurrency Control),并发控制可以解决临界资源操作时不一致的情况产生,保证数据一致性常见的手段就是锁和数据多版本(Multi Version)

直接加锁

这种方式会导致被加锁的资源都被锁住,读取任务也无法执行直到锁释放,所有执行的任务相当于串行化方式,简单粗暴,不能并发

共享锁(Shared Locks)简称为 S 锁

读取数据时候可以加 S 锁。

共享 (S) 锁允许并发事务读取 (SELECT) 一个资源。资源上存在共享 (S) 锁时,任何其它事务都不能修改数据。一旦已经读取数据,便立即释放资源上的共享 (S) 锁,除非将事务隔离级别设置为可重复读或更高级别,或者在事务生存周期内用锁定提示保留共享 (S) 锁。

排它锁 (Exclusive Locks)简称为 X 锁

修改数据时候加 X 锁。

排它 (X) 锁可以防止并发事务对资源进行访问。其它事务不能读取或修改排它 (X) 锁锁定的数据。

共享锁之间可以并行,排它锁和共享锁之间互斥,也就是说只要共享锁开启没有释放掉的时候,更新锁是不能抢占的,此时其他读取同资源的操作可以进行读取不受限制;同理排它锁开启时候只要没有释放其他不管是排它锁还是共享锁都不可以抢占资源直到锁释放。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值