MySQL中的事务特性以及隔离机制如下:
事务特性(ACID):
- 原子性(Atomicity):一个事务被视为一个不可分割的最小工作单元,要么全部执行完成,要么完全不执行。
- 一致性(Consistency):事务在执行前后,数据库的状态必须保持一致。即事务开始前和结束后,数据库的数据完整性约束没有被破坏。
- 隔离性(Isolation):每个事务的操作都应该与其他并发事务隔离,即它们不能相互干扰。
- 持久性(Durability):一旦事务提交,那么对数据库的修改将永久保存,即使数据库发生故障也不会丢失。
隔离级别:
- 读未提交(Read Uncommitted):允许事务读取尚未提交的数据,可能导致脏读、不可重复读、幻读的问题。
- 读已提交(Read Committed):只允许事务读取已经提交的数据,解决了脏读的问题,但仍可能出现不可重复读和幻读。
- 可重复读(Repeatable Read):确保事务可以多次重复地读取同样的数据,并保证在事务执行期间其他事务不会修改这些数据,解决了脏读和不可重复读的问题,但仍可能出现幻读。
- 串行化(Serializable):对事务进行串行化顺序执行,完全解决了所有并发问题,但可能导致性能下降。
不同隔离级别解决的问题:
- 脏读(Dirty Read):一个事务读取到了另一个事务未提交的数据。隔离级别中,读已提交及以上级别都解决了脏读的问题。
- 不可重复读(Non-repeatable Read):在同一事务内,多次读取同一行数据时,由于其他事务的修改,导致读取结果不一致。隔离级别中,可重复读及以上级别解决了不可重复读的问题。
- 幻读(Phantom Read):在同一事务内,多次查询得到的结果集不一致,因为其他事务插入了符合查询条件的新数据行。隔离级别中,串行化级别解决了幻读的问题。
验证不同隔离级别的问题解决: 您可以使用以下sql语句设置并测试不同的隔离级别:
-- 设置隔离级别
SET TRANSACTION ISOLATION LEVEL <isolation_level>;
-- 执行SQL语句
-- 提交事务
COMMIT;
其中 <isolation_level>
可以替换成 READ UNCOMMITTED
、READ COMMITTED
、REPEATABLE READ
或 SERIALIZABLE
,分别对应不同的隔离级别。
然后执行一系列涉及并发读取和写入的测试操作,观察是否出现脏读、不可重复读或幻读的问题。您可以尝试在不同的隔离级别下进行多个客户端的并发操作,看看它们是否会相互影响。
请注意,在测试过程中,要使用足够的样本数据和并发操作来模拟真实场景。同时,由于串行化级别会锁定数据,可能会导致性能下降,因此在实际应用中需要权衡隔离级别和性能之间的关系,并选择合适的隔离级别。
假设我们有一个名为 customers
的表,包含 id
和 balance
列。使用下面的 SQL 语句创建并填充该表:
CREATE TABLE customers (
id INT PRIMARY KEY,
balance DECIMAL(10, 2)
);
INSERT INTO customers (id, balance) VALUES
(1, 1000.00),
(2, 2000.00);
现在,让我们尝试在不同的隔离级别下进行验证:
- READ UNCOMMITTED(读未提交)
-- 连接1
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
START TRANSACTION;
UPDATE customers SET balance = balance - 500 WHERE id = 1;-- 连接2
SELECT * FROM customers;
-- 结果:能够看到未提交的数据变化,例如 balance 减少了 500COMMIT;
-- 连接2
SELECT * FROM customers;
-- 结果:已经看不到未提交的数据变化 - READ COMMITTED(读已提交)
-- 连接1
SET TRANSACTION ISOLATION LEVEL READ COMMITTED;
START TRANSACTION;
UPDATE customers SET balance = balance - 500 WHERE id = 1;-- 连接2
SELECT * FROM customers;
-- 结果:无法看到未提交的数据变化COMMIT;
-- 连接2
SELECT * FROM customers;
-- 结果:现在可以看到修改后的数据 - REPEATABLE READ(可重复读)
-- 连接1
SET TRANSACTION ISOLATION LEVEL REPEATABLE READ;
START TRANSACTION;
SELECT * FROM customers WHERE balance > 1500;-- 连接2
UPDATE customers SET balance = balance + 100 WHERE id = 3;-- 连接1
SELECT * FROM customers WHERE balance > 1500;
-- 结果:不会看到连接2中新增的数据COMMIT;
-- 连接1
SELECT * FROM customers WHERE balance > 1500;
-- 结果:仍然不会看到连接2中新增的数据 - SERIALIZABLE(串行化)
-- 连接1
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
START TRANSACTION;
SELECT * FROM customers WHERE balance > 1500;-- 连接2
UPDATE customers SET balance = balance + 100 WHERE id = 3;-- 连接1
SELECT * FROM customers WHERE balance > 1500;
-- 结果:不会看到连接2中新增的数据COMMIT;
-- 连接1
SELECT * FROM customers WHERE balance > 1500;
-- 结果:仍然不会看到连接2中新增的数据
样例
string 字符串 set name "John"
LIST 列表 lpush numbers 5 4 3 2 1
SET 集合 sadd fruits apple orange banana
ZSET 有序集合 zadd leaderboard 100 "John" 200 "Alice" 50 "Bob"
HASH 哈希 hset user id 1 name "John" age 30
BITMAPS 地图 setbit user:1:online 0 1
HYPERLOGLOG 基数估计 PFADD visitors user1 user2 user3
GEOSPATIAL 地理位置 GEOADD cities -122.4194 37.7749 "San Francisco"