「持久性(Durability)」:一旦事务提交,其结果就被永久保存。
START TRANSACTION; -- 更新订单状态 UPDATE orders SET status = 'paid' WHERE id = 1001; -- 插入支付记录 INSERT INTO payment_records (order_id, amount) VALUES (1001, 99.99); -- 假设支付记录插入失败,整个事务需要回滚 ROLLBACK; -- 如果以上操作都成功,则提交事务 COMMIT;如果在支付过程中发生任何问题,整个事务将回滚,就好像这次支付从未发生过。
START TRANSACTION; -- 用户A账户扣款 UPDATE accounts SET balance = balance - 100 WHERE user_id = 'A'; -- 用户B账户加款 UPDATE accounts SET balance = balance + 100 WHERE user_id = 'B'; COMMIT;通过事务,我们确保了转账的一致性,保证了无论发生什么情况,账户的总金额都保持不变。
-- 用户1开始事务 START TRANSACTION ISOLATION LEVEL SERIALIZABLE; -- 查询商品数量 SELECT stock FROM products WHERE id = 'XYZ'; -- 若商品数量足够,进行抢购 UPDATE products SET stock = stock - 1 WHERE id = 'XYZ'; COMMIT; -- 用户2的事务将等待用户1的事务完成,保持隔离性通过设置合适的隔离级别,我们可以避免脏读、不可重复读和幻读等问题。
START TRANSACTION; -- 插入论文记录 INSERT INTO papers (title, abstract, author) VALUES ('A Study on MySQL', '...', 'Dr. Smith'); COMMIT;无论系统发生了何种故障,只要事务提交了,这篇论文的记录就永久地存储在了数据库中。
-- 事务的开始 START TRANSACTION; -- 执行一系列的DML操作 UPDATE accounts SET balance = balance - 100 WHERE user_id = 'A'; UPDATE accounts SET balance = balance + 100 WHERE user_id = 'B'; -- 如果一切顺利 COMMIT; -- 此时,InnoDB会将事务的所有更改写入重做日志并刷盘 -- 如果操作失败 ROLLBACK; -- InnoDB利用撤销日志回滚到事务开始前的状态当系统崩溃时,重做日志用于恢复已提交的事务,而撤销日志用于回滚未提交的事务。
-- 假设我们有一张账户表 accounts -- 开启日志输出 SET global general_log = 1; SET global log_output = 'table'; START TRANSACTION; -- 假设账户A的转账操作 UPDATE accounts SET balance = balance - 100 WHERE user_id = 'A'; -- 假设账户B的收款操作 UPDATE accounts SET balance = balance + 100 WHERE user_id = 'B'; -- 提交事务前,查看当前的日志记录 SELECT * FROM mysql.general_log WHERE command_type = 'Query' AND argument LIKE '%accounts%'; -- 提交事务 COMMIT; -- 现在再次查看日志,观察事务提交后的日志变化 SELECT * FROM mysql.general_log WHERE command_type = 'Query' AND argument LIKE '%accounts%'; -- 关闭日志输出 SET global general_log = 0;在这个例子中,我们通过开启MySQL的general log来观察事务中的数据库操作。一旦提交,相关的重做日志(不直接显示在general log中)会记录这些更改,以便于在系统崩溃后进行恢复。
-- 假设有两张表:orders(订单表)和order_details(订单详情表) -- orders表 CREATE TABLE orders ( order_id INT PRIMARY KEY, order_date DATE NOT NULL ); -- order_details表 CREATE TABLE order_details ( detail_id INT PRIMARY KEY, order_id INT NOT NULL, product_name VARCHAR(255) NOT NULL, quantity INT DEFAULT 1, FOREIGN KEY (order_id) REFERENCES orders(order_id) ); -- 插入数据时,外键约束会确保只有存在于orders表中的order_id才能被添加到order_details表 -- 这保证了数据库的引用完整性,从而保持一致性 INSERT INTO orders (order_id, order_date) VALUES (1, '2023-04-01'); INSERT INTO order_details (detail_id, order_id, product_name) VALUES (101, 1, 'Widget A'); -- 试图插入一个不存在的order_id会导致错误,从而防止了一致性的破坏 INSERT INTO order_details (detail_id, order_id, product_name) VALUES (102, 999, 'Widget B'); -- ERROR
-- 设置会话的隔离级别为可重复读(默认) SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ; -- 会话1:开始事务并读取数据 START TRANSACTION; SELECT * FROM products WHERE id = 'XYZ'; -- 在另一个会话中更新了相同的数据 -- 会话2: START TRANSACTION; UPDATE products SET stock = stock - 1 WHERE id = 'XYZ'; COMMIT; -- 会话1中再次读取相同的数据 SELECT * FROM products WHERE id = 'XYZ'; -- 由于MVCC的作用,会话1中的数据仍然是旧的数据,保持了隔离性 -- 提交事务 COMMIT;在这个例子中,尽管会话2中的数据已经被更新,但由于MVCC的作用,会话1中的读取操作依然可以看到它事务开始时的数据状态,符合可重复读(REPEATABLE READ)隔离级别的要求。
-- 提交事务 COMMIT; -- 查看InnoDB的重做日志信息 SHOW ENGINE INNODB STATUS\G在提交事务后,我们可以通过SHOW ENGINE INNODB STATUS命令来查看InnoDB的内部状态,包括重做日志的相关信息。这些信息可以帮助我们理解事务的持久化过程,虽然它不直接展示日志内容,但它提供了日志活动的概览,我们可以从中看到重做日志的写入和刷盘操作。