文章目录
MySQL事务
事务(Transaction)是数据库管理系统(DBMS)中的一个核心概念,它确保了一系列数据库操作要么全部成功,要么全部失败,从而维护数据库的完整性和一致性。
事务的四个基本特性(ACID)
1. 原子性(Atomicity)
原子性是指事务是一个不可分割的工作单位,事务中的操作要么全部执行,要么全部不执行。这确保了事务的完整性,防止了部分操作成功而部分操作失败的情况。
- 原子性的实现:数据库系统通常通过日志(如重做日志和撤销日志)来实现原子性。在事务开始时,数据库系统会记录事务的初始状态;在事务执行过程中,系统会记录每一步操作;如果事务成功,则提交这些操作;如果事务失败,则使用撤销日志将数据库恢复到事务开始前的状态。
- 原子性的重要性:原子性保证了数据库的一致性和可靠性。在上面的转账案例中,如果扣款操作成功而加款操作失败,那么数据库的状态就会不一致,导致资金流失或重复记账。原子性确保了这种不一致的情况不会发生。
2. 一致性(Consistency)
一致性是指事务将数据库从一个一致状态变换到另一个一致状态。在事务开始之前和事务结束以后,数据库的完整性约束没有被破坏。
- 一致性的实现:数据库系统通过定义各种完整性约束(如主键约束、外键约束、唯一性约束等)来确保数据的一致性。事务在执行过程中必须遵守这些约束,否则事务将被回滚。
- 一致性的重要性:一致性是数据库系统的核心目标之一。它确保了数据的准确性和可靠性,防止了数据的不一致和错误。在上面的转账案例中,一致性确保了转账前后A和B的存款总额保持不变。
3. 隔离性(Isolation)
隔离性是指在并发环境中,当不同的事务同时操纵相同的数据时,每个事务都有各自的完整数据空间。事务之间的操作不会互相干扰。
-
隔离性的实现:数据库系统通过锁机制、时间戳排序、多版本并发控制等技术来实现隔离性。这些技术确保了事务在并发执行时不会互相干扰,从而保证了数据的一致性和完整性。
-
隔离性的重要性:隔离性防止了并发事务之间的冲突和干扰。它确保了事务的独立性,使得事务可以在不受其他事务影响的情况下执行。在上面的案例中,隔离性防止了脏读、不可重复读和幻读等一致性问题。
-
隔离级别:
- 未提交读(Read Uncommitted):允许脏读,即允许一个事务看到其他事务未提交的修改。这种隔离级别最低,性能最高,但一致性最差。
- 提交读(Read Committed):只允许一个事务看到其他事务已经提交的修改。这种隔离级别可以防止脏读,但不能防止不可重复读和幻读。
- 可重复读(Repeatable Read):确保如果在一个事务中执行两次相同的SELECT语句,都能得到相同的结果。这种隔离级别可以防止脏读和不可重复读,但不能完全防止幻读(在某些数据库系统中,如MySQL的InnoDB引擎,通过间隙锁等技术可以进一步防止幻读)。
- 串行化(Serializable):将事务完全隔离,使得它们按顺序执行。这种隔离级别最高,一致性最好,但性能最低。
4. 持久性(Durability)
持久性是指事务一旦提交,它对数据库所做的更改就会永久地保存在数据库中,即使系统发生故障也不会丢失。
- 持久性的实现:数据库系统通常通过将事务的更改写入到持久存储设备(如磁盘)上来实现持久性。在事务提交之前,这些更改可能只存在于内存中;但在事务提交之后,这些更改就会被写入到磁盘上,从而确保它们不会丢失。
- 持久性的重要性:持久性确保了数据的可靠性和持久性。它使得事务的更改即使在系统崩溃或重启后也能被恢复和访问。在上面的案例中,持久性确保了转账操作的结果即使在断电后也能被保留和查询。
在事务管理中,原子性、一致性、隔离性和持久性共同构成了事务的ACID特性。这些特性确保了事务的完整性、一致性和可靠性。原子性是基础,它确保了事务的不可分割性;隔离性是手段,它防止了并发事务之间的冲突和干扰;一致性是目的,它确保了数据的一致性和准确性;持久性是结果,它确保了事务的更改能够永久地保存在数据库中。通过遵循ACID特性,数据库系统能够在并发环境下提供强大的数据保护能力,使得数据库能够高效地处理各种复杂的应用场景。
事务的应用场景
事务广泛应用于需要高数据一致性和可靠性的系统中,如:
- 银行系统:处理账户转账、存款、取款等操作,确保资金流动的准确性。
- 保险系统:处理保单的创建、修改、取消等操作,确保保单数据的准确性。
- 证券交易系统:处理股票的买卖、资金的划转等操作,确保交易数据的准确性。
- 电子商务系统:处理订单的创建、支付、发货等操作,确保订单状态的正确性。
事务的管理
事务的管理包括事务的开始、提交和回滚等操作,通常由DBMS提供的事务管理器来负责。
- 开始事务:通常通过显式地声明一个事务的开始,或者在执行第一个DML(数据操纵语言)操作时自动开始。
- 提交事务:当事务中的所有操作都成功执行后,通过提交(commit)操作来使这些改变永久生效。
- 回滚事务:如果事务中的某个操作失败,或者由于某种原因需要撤销事务,则通过回滚(rollback)操作来撤销事务中的所有改变,恢复到事务开始前的状态。
并发控制
在并发环境下,多个事务可能同时访问和修改数据库。为了确保数据的一致性和完整性,DBMS提供了多种并发控制机制,如锁(locking)、时间戳排序(timestamp ordering)和多版本并发控制(MVCC)等。
- 锁:通过锁定数据库资源来防止并发事务之间的冲突。锁可以是共享锁(允许多个事务同时读取)或排他锁(只允许一个事务写入)。
- 时间戳排序:给每个事务分配一个唯一的时间戳,并根据时间戳的顺序来处理事务,以避免冲突。
- 多版本并发控制:为数据库中的每个数据项维护多个版本,以允许并发事务读取不同版本的数据,从而减少冲突。
事务控制语句详解及案例分析
在数据库管理中,事务控制是非常重要的,它确保了数据的一致性和完整性。MySQL 提供了丰富的事务控制语句,包括 BEGIN
/START TRANSACTION
、COMMIT
、ROLLBACK
、SAVEPOINT
和 ROLLBACK TO SAVEPOINT
等。此外,还可以通过 SET
语句来控制事务的自动提交行为。
事务控制语句
- BEGIN 或 START TRANSACTION:显式地开启一个事务。在事务开启后,所有的操作都会被视为一个整体,直到执行
COMMIT
或ROLLBACK
。 - COMMIT 或 COMMIT WORK:提交事务,使所有已对数据库进行的修改变为永久性的。提交后,事务中的更改将被保存到数据库中,并且对其他事务可见。
- ROLLBACK 或 ROLLBACK WORK:回滚事务,撤销正在进行的所有未提交的修改。回滚后,数据库将恢复到事务开始之前的状态。
- SAVEPOINT S1:在事务中创建一个回滚点。一个事务中可以有多个回滚点,它们允许你将事务回滚到特定的点,而不是完全回滚到事务的开始。
- ROLLBACK TO [SAVEPOINT] S1:将事务回滚到指定的回滚点。如果指定了回滚点名称(如
S1
),则事务将回滚到该点;如果没有指定,则回滚到事务的开始。
案例分析
- 测试提交事务
在这个案例中,开启了一个事务,更新了A的money字段,然后提交了事务。use xy101; create table account( id int(10) primary key not null, name varchar(40), money double ); insert into account values(1,'A',1000); insert into account values(2,'B',1000); begin; update account set money= money - 100 where name='A'; commit; quit # 在另一个会话中查看结果 mysql -u root -p use xy101; select * from account; -- 此时A的money应为900
提交后,可以在另一个会话中看到更改的结果。 - 测试回滚事务
在这个案例中,尝试了增加A的money字段,但随后回滚了事务。begin; update account set money= money + 100 where name='A'; rollback; # 在另一个会话中查看结果(或同一会话中重新查询) select * from account; -- 此时A的money仍为900,因为事务被回滚了
因此,更改没有被保存到数据库中。 - 测试多点回滚
该测试主要展示了事务处理中的一个重要特性:部分回滚
在这个案例中,创建了多个回滚点,并进行了多次更新和插入操作。然后,我们将事务回滚到begin; update account set money= money + 100 where name='A'; SAVEPOINT S1; update account set money= money + 100 where name='B'; SAVEPOINT S2; insert into account values(3,'C',1000); select * from account; -- 查看当前状态 ROLLBACK TO S1; -- 回滚到S1点 select * from account; -- 查看回滚后的状态
S1
点,此时只有A的money字段被增加了100,而B的money字段和C的插入操作都被撤销了。这意味着从S1点到事务结束之间的所有操作(更新B的money和插入C的记录)都被撤销了,而S1点之前的操作(更新A的money)则保留了下来。
使用 SET
设置控制事务
- SET AUTOCOMMIT=0:禁止自动提交。在自动提交被禁止的情况下,你需要显式地提交或回滚事务。这允许你将多个操作组合成一个事务。
- SET AUTOCOMMIT=1:开启自动提交。在自动提交被开启的情况下,每个单独的SQL语句都会被视为一个事务,并在执行后自动提交。这是MySQL的默认行为。
- SHOW VARIABLES LIKE ‘AUTOCOMMIT’:查看当前会话的自动提交设置。
示例
use xy101;
select * from account;
SET AUTOCOMMIT=0;
update account set money= money + 100 where name='B';
select * from account; -- 此时在另一个会话中看不到更改,因为事务未提交
quit
# 在另一个会话中查看结果(或重启同一会话并重新连接)
mysql -u root -p
use xy101;
select * from account; -- 此时B的money仍为1000(或之前的值),因为事务未提交且会话已断开
在这个示例中,禁用了自动提交,然后更新了B的money字段。但是,由于没有提交事务并且断开了会话连接,因此更改没有被保存到数据库中。
这展示了在禁用自动提交时,需要显式地提交事务以保存更改的重要性。
总结
基础要点
事务特性:
事务特性 | 描述 |
---|---|
原子性 | 把事务中的所有操作看作为一个不可分割的工作单元,要么都执行,要么都不执行 |
一致性 | 保证事务开始前和事务结束后数据的完整和一致 |
隔离性 | 使多个事务并发操作同一个数据时,每个事务都有自己各自独立的数据空间,事务的执行不会受到其它事务干扰。可以通过设置隔离级别来解决不同的一致性问题 |
持久性 | 当事务被提交以后,事务中的命令操作修改的结果会被持久化保存,且不会被回滚 |
隔离级别:
隔离级别 | 允许的操作类型 | 备注 |
---|---|---|
未提交读 (Read Uncommitted) | 脏读、不可重复读、幻读 | 最低级别的隔离,可能会读取到其他事务未提交的更改 |
提交读 (Read Committed) | 不允许脏读,允许不可重复读、幻读 | 只能读取到其他事务已经提交的更改,但同一事务内多次读取可能结果不同 |
可重复读 (Repeatable Read) | 不允许脏读、不可重复读,有条件的允许幻读(使用InnoDB存储引擎可以解决) | 保证同一事务内多次读取结果一致,但某些情况下可能产生幻读,InnoDB通过间隙锁等方式解决 |
串行读 (Serializable) | 都不允许(相当于锁表) | 最高级别的隔离,通过锁表保证事务的完全隔离,但会严重影响数据库的并发性能 |
注意:
- 原子性、一致性和持久性是事务本身的特性,与隔离级别没有直接的对应关系,因此在隔离级别列下标记为“-”。
- 隔离级别列则详细列出了四种不同的隔离级别以及它们各自允许或不允许的操作类型(脏读、不可重复读、幻读)。
事务管理命令
事务管理和回滚点
-- 显示的开启一个事务
begin;
-- 事务性操作(示例)
insert into 表名 (列1, 列2) values (值1, 值2);
update 表名 set 列 = 新值 where 条件;
delete from 表名 where 条件;
-- 在事务中创建回滚点
savepoint XX;
-- 在事务中回滚到指定的回滚点位置
rollback to XX;
-- 提交事务,使所有更改永久生效
commit;
-- 或者回滚事务,撤销所有更改
rollback;
自动提交设置
-- 设置会话级自动提交为关闭(0)或开启(1)
set session autocommit = 0; -- 关闭自动提交
set session autocommit = 1; -- 开启自动提交
-- 设置全局级自动提交为关闭(0)或开启(1),需要重新登录后生效
set global autocommit = 0; -- 关闭自动提交
set global autocommit = 1; -- 开启自动提交
-- 查看会话级自动提交设置
show session variables like 'autocommit';
-- 注意:原命令中的 'lile' 应为 'like',查看全局级自动提交设置
show global variables like 'autocommit';
隔离级别设置和查看
-- 设置会话级的隔离级别,仅在当前会话中立即有效
set session transaction isolation level <隔离级别>;
例如:set session transaction isolation level repeatable read;
-- 设置全局级的隔离级别,可在所有会话中有效,需要重新登录后生效
set global transaction isolation level <隔离级别>;
例如:set global transaction isolation level serializable;
-- 查看会话级的隔离级别
show session variables like '%isolation%';
-- 查看全局级的隔离级别
show global variables like '%isolation%';
注意事项
- 在使用
set global
命令更改全局变量时,需要具有相应的权限,并且更改将在新会话中生效,当前会话不受影响。 - 隔离级别包括:
read uncommitted
、read committed
、repeatable read
和serializable
。选择合适的隔离级别取决于应用程序的需求和性能考虑。 - 自动提交模式决定了每个独立的SQL语句是否自动作为一个事务提交。在关闭自动提交模式下,需要显式地使用
commit
或rollback
来结束事务。 - 使用回滚点时,可以在事务中创建多个回滚点,并根据需要回滚到特定的回滚点。