容桂销售型网站建设,备案信息查询官网,wordpress栏目seo,宁波五金网站建设目录 一、什么是事务#xff1f; 1.1.事务的定义 1.2.事务的基本语句 1.3.事务的四大特性#xff08;ACID#xff09; 二、数据库的并发控制 2.1.什么是并发及并发操作带来的影响#xff1f; 2.2.并发操作带来的隔离级别 三、使用事务的场景 3.1.银行转账场景示例 3.2.模拟… 目录 一、什么是事务 1.1.事务的定义 1.2.事务的基本语句 1.3.事务的四大特性ACID 二、数据库的并发控制 2.1.什么是并发及并发操作带来的影响 2.2.并发操作带来的隔离级别 三、使用事务的场景 3.1.银行转账场景示例 3.2.模拟丢失修改、不可重复读、读脏数据 一、什么是事务
1.1.事务的定义
MySQL事务是数据库操作的一个基本单元它确保一组操作要么全部成功要么全部失败。事务的主要目的是保证数据的一致性和完整性。
1.2.事务的基本语句
一个事务由应用程序的一组操作序列组成它以 BEGIN TRANSACTION语句开始以 END TRANSACTION 结束语句。
事务定义的语句如下:
BEGIN TRANSACTION: 事务开始。END TRANSACTION:事务结束。COMMIT:事务提交。该操作表示事务成功地结束它将通知事务管理器该事务的所有更新操作现在可以被提交或永久地保留。ROLLBACK:事务回滚。该操作表示事务非成功地结束它将通知事务管理器出故障了数据库可能处于不一致状态该事务的所有更新操作必须回滚或撤销。这意味着将撤销该事务对数据库的更新。这样数据库恢复到该事务执行第一条语句之前的状态。
典型示例
典型的例子是银行转账业务。对“从账户 A 转入账户 B 金额x元”业务站在顾客角度来看转账是一次单独操作而站在数据库系统的角度它至少是由两个操作组成的第一步从账户A减去x元第二步给账户B加上x元。下面是银行转账事务的伪代码: BEGIN TRANSACTION read(A); /*读账户A的余额*/ AA-x; IF(A0)THEN print(金额不足不能转账); ROLLBACK; /*撤销该事务回到事务执行前的状态* ELSE write(A); /*写入账户A的余额*/ read(B); BB1; write(B); COMMIT; /*提交事务*/ ENDIF; END TRANSACTION 1.3.事务的四大特性ACID
原子性Atomicity事务中的所有操作要么全部完成要么全部不完成。如果事务中的任何操作失败整个事务将回滚到初始状态。一致性Consistency事务执行前后数据库的状态必须保持一致。这意味着事务必须遵循数据库的约束和规则。隔离性Isolation多个事务并发执行时一个事务的操作不会影响其他事务。每个事务都感觉不到其他事务的存在。持久性Durability一旦事务提交它对数据库的修改就是永久性的即使系统发生故障也不会丢失。
二、数据库的并发控制
2.1.什么是并发及并发操作带来的影响
所谓并发操作是指在多用户共享的系统中许多用户可能同时对同一数据进行操作。这种机制就有可能导致其他用户想要得到原始数据但由于其他用户的读写操作导致数据已经进行修改等情况的产生。 通常并发操作导致数据的不一致性主要有三类: 1.丢失修改 如图 12-7(a)所示事务 T!、T,都是对數据 A 做減1操作。事务T,在时劍ち把A 修改后的值15写入数据库但事务T在时刻t再把它对A减1后的值15写入。两个事务都是对 A的值进行减1操作并且都执行成功但A中的值却只减了1。现实的例子如售票系统同时售出了两张票但数据库里的存票却只减了一张造成数据的不一致。原因在于T事务对数据库的修改被 T事务覆盖而丢失了破坏了事务的隔离性。 2.不可重复读 如图 12-7(b)所示事务 T读取 A、B 的值后进行运算事务 T在 t时刻对 B的值做了修改以后事务 T又重新读取 A、B 的值再运算同一事务内对同一组数据的相同运算结果不同显然与事实不相符。同样是事务 工干扰了事务 T的独立性。 3.读脏数据 如图 12-7(c)所示事务 T对数据 ℃ 修改之后在 t时刻事务 T读取修改后的 ℃ 值做处理之后事务 T回滚数据 ℃ 恢复了原来的值事务 T对C所做的处理是无效的它读的是被丢掉的垃圾值。 其主要原因是事务的并发操作破坏了事务的隔离性。DBMS的并发控制子系统负责协调并发事务的执行保证数据库的完整性不受破坏避免用户得到不正确的数据。
2.2.并发操作带来的隔离级别
并发操作对应产生了由于不同隔离级别所产生的不同并发问题。一般规律也是隔离级别越高数据一致性越强但并发性能相应就越低。
并发问题读未提交Read Uncommitted读已提交Read committed可重复读Repeatable Read串行化Serializable脏读Dirty Read×√√√不可重复读××√√ 幻读Phantom ××MySQL在可重复读级别通过Next-Key锁解决幻读√丢失更新××不能完全解决√
幻读和不可重复读
类型关注点变化不可重复读同一条记录的数据变化余额从 1000 → 900值变化幻读结果集的行数变化第一次查有 5 条第二次变 6 条。
三、使用事务的场景
3.1.银行转账场景示例
测试事务的一致性要么同时成功要么同时失败
-- 表结构设计
drop table book;
CREATE TABLE book (recID INT(11) PRIMARY KEY AUTO_INCREMENT,title VARCHAR(50) NOT NULL,type VARCHAR(20) NOT NULL,price DECIMAL(10,2) NOT NULL
) ENGINEInnoDB DEFAULT CHARSETutf8mb4;show TABLES;select * from book b;
-- 初始数据
INSERT INTO book (title, type, price) VALUES
(Java Programming, Computer, 16.00),
(Java EE Technology, Computer, 5.00),
(Information System, Computer, 15.00);-- 事务操作语句
BEGIN;
-- 批量降价8元
UPDATE book SET price price - 8 WHERE recID 1;
UPDATE book SET price price - 8 WHERE recID 2;
UPDATE book SET price price - 8 WHERE recID 3;-- 验证价格是否不低于0
SELECT * FROM book WHERE price 0;-- 根据验证结果选择提交或回滚
COMMIT; -- 无负值时提交
ROLLBACK; -- 出现负值时回滚
验证 验证价格是否不低于0因为出现负值我们执行回滚操作看数据是否会回到我们最开始的状态值。 3.2.模拟丢失修改、不可重复读、读脏数据
由于mysql其自身的默认隔离级别就已经是可重复读即使并发执行也不会产生丢失修改和不可重复读问题。
-- 查看当前会话的隔离级别MySQL 5.7 和 MariaDBSELECT transaction_isolation;-- 查看全局隔离级别SELECT global.transaction_isolation;-- mysql中的默认隔离级别是REPEATABLE-READ 模拟
-- 1. 表结构设计以银行账户为例
CREATE TABLE account (id INT PRIMARY KEY AUTO_INCREMENT,name VARCHAR(50) NOT NULL,balance DECIMAL(10, 2) NOT NULL -- 账户余额
);
-- 插入初始数据
INSERT INTO account (name, balance) VALUES (Alice, 1000.00);-- 2. 模拟不可重复读
-- 现象事务A多次读取同一数据事务B修改并提交后事务A两次读取结果不一致。
-- 隔离级别READ COMMITTED读已提交
-- 操作步骤-- 事务A首次读取
BEGIN;
SELECT balance FROM account WHERE name Alice; -- 结果1000.00-- 事务B修改并提交
BEGIN;
UPDATE account SET balance 900.00 WHERE name Alice;
COMMIT; -- 修改生效-- 事务A再次读取
SELECT balance FROM account WHERE name Alice; -- 结果900.00与第一次不一致
COMMIT;
-- 结果事务A两次读取结果不同即不可重复读。-- 3. 模拟丢失修改
-- 现象两个事务同时读取并修改同一数据后提交的事务覆盖前者的修改。
-- 隔离级别READ UNCOMMITTED读未提交或 READ COMMITTED
-- 操作步骤-- 事务A读取并修改
BEGIN;
SELECT balance FROM account WHERE name Alice; -- 读取1000.00
UPDATE account SET balance 1000.00 - 100 900.00 WHERE name Alice;-- 事务B同时读取并修改
BEGIN;
SELECT balance FROM account WHERE name Alice; -- 仍读取1000.00未提交的数据
UPDATE account SET balance 1000.00 - 200 800.00 WHERE name Alice;
COMMIT; -- 先提交-- 事务A提交
COMMIT; -- 覆盖事务B的修改
-- 结果余额变为 900.00事务B的修改丢失正确应为 700.00。
开启事务A B
事务A读取到的值 事务B修改提交之后 事务A再次读取