1. 什么是事务?
在数据库管理系统中,事务是指一组数据库操作,这些操作要么全部执行成功,要么全部执行失败。事务可以确保数据库的一致性和完整性,以及支持并发访问和并发控制。
事务具有以下四个特性,通常被称为ACID特性:
原子性(Atomicity):事务中的所有操作要么全部成功,要么全部失败。如果事务中的任何操作失败,那么整个事务将被回滚到初始状态,不会对数据库产生任何影响。
一致性(Consistency):事务的执行不会破坏数据库的一致性。在事务开始之前和结束之后,数据库必须处于一致的状态。
隔离性(Isolation):并发事务之间是相互隔离的,每个事务的操作对其他事务是不可见的。事务的隔离级别可以控制并发事务之间的可见性和影响。
持久性(Durability):一旦事务被提交,其结果将永久保存在数据库中,即使在系统故障的情况下也不会丢失。
2. 事务的例子
为了更好地理解事务的概念与特性,我们来看一些例子。
2.1 转账事务
假设我们有一个银行应用程序,需要实现转账功能。当用户A向用户B转账时,我们希望这个操作是原子的,要么全部成功,要么全部失败。
首先,我们创建一个accounts
表来存储用户的账户信息:
CREATE TABLE accounts (
id INT PRIMARY KEY,
name VARCHAR(50),
balance DECIMAL(10, 2)
);
复制
复制
然后,我们插入一些测试数据:
复制
INSERT INTO accounts (id, name, balance) VALUES (1, 'Alice', 1000.00);
INSERT INTO accounts (id, name, balance) VALUES (2, 'Bob', 500.00);
复制
复制
现在,我们可以使用事务来实现转账功能:
DELIMITER //
CREATE PROCEDURE TransferFunds()
BEGIN
START TRANSACTION;
-- 查询用户A的余额
SELECT balance INTO @balance_a FROM accounts WHERE id = 1;
-- 查询用户B的余额
SELECT balance INTO @balance_b FROM accounts WHERE id = 2;
-- 检查用户A的余额是否足够
IF @balance_a >= 100.00 THEN
-- 更新用户A的余额
UPDATE accounts SET balance = balance - 100.00 WHERE id = 1;
-- 更新用户B的余额
UPDATE accounts SET balance = balance + 100.00 WHERE id = 2;
-- 提交事务
COMMIT;
ELSE
-- 回滚事务
ROLLBACK;
END IF;
END //
DELIMITER ;
复制
复制
-- 调用存储过程
CALL TransferFunds();
复制
复制
在这个例子中,我们首先查询用户A和用户B的余额。然后,我们检查用户A的余额是否足够进行转账。如果足够,我们更新用户A和用户B的余额,并提交事务。否则,我们回滚事务。
2.2 订单事务
假设我们有一个在线商店应用程序,需要实现下订单功能。当用户下订单时,我们希望将订单信息插入到orders
表中,并从用户的账户中扣除相应的金额。
首先,我们创建一个orders
表来存储订单信息:
CREATE TABLE orders (
id INT PRIMARY KEY,
user_id INT,
total DECIMAL(10, 2)
);
复制
复制
然后,我们插入一些测试数据:
复制
INSERT INTO orders (id, user_id, total) VALUES (1, 1, 100.00);
INSERT INTO orders (id, user_id, total) VALUES (2, 2, 200.00);
复制
现在,我们可以使用事务来实现下订单功能:复制
DELIMITER //
CREATE PROCEDURE ProcessOrder()
BEGIN
-- 开始事务
START TRANSACTION;
-- 查询订单信息
SELECT total INTO @total FROM orders WHERE id = 1;
-- 查询用户余额
SELECT balance INTO @balance FROM accounts WHERE id = 1;
-- 检查用户余额是否足够支付订单
IF @balance >= @total THEN
-- 插入订单信息(注意:这里的订单ID不应该硬编码为3,应该是动态生成的)
INSERT INTO orders (user_id, total) VALUES (1, @total);
-- 更新用户余额
UPDATE accounts SET balance = balance - @total WHERE id = 1;
-- 提交事务
COMMIT;
ELSE
-- 回滚事务
ROLLBACK;
END IF;
END //
DELIMITER ;
复制
复制
-- 调用存储过程
CALL ProcessOrder();
复制
复制
在这个例子中,我们首先查询订单的总金额和用户的余额。然后,我们检查用户的余额是否足够支付订单。如果足够,我们插入订单信息,并更新用户的余额。最后,我们提交事务。如果用户的余额不足以支付订单,我们回滚事务。