1、事务
事务是逻辑上的一组操作,要么都执行,要么都不执行。
事务控制语法
- 事务开始
begin;
- 事务提交,提交后就会写入物理磁盘中去
commit;
- 事务回滚,事务提交后,无法回滚
rollback;
事务的四大特性(ACID)
原子性(atomicity): 事务是最小的执行单位,不允许分割。事务的原子性确保动作要么全部完成,要么完全不起作用
一致性(consistency): 执行事务前后,数据保持一致,例如转账业务中,无论事务是否成功,转账者和收款人的总额应该是不变的;
隔离性(isolation): 并发访问数据库时,一个用户的事务不被其他事务所干扰,各并发事务之间数据库是独立的
持久性(durability): 一个事务被提交之后。它对数据库中数据的改变是持久的,即使数据库发生故障也不应该对其有任何影响。
事务自动提交
SET autocommit = 0|1|ON|OFF;
2、并发事务带来的问题
脏读(Dirty Read): 一个事务正在对数据进行修改,在这个事务提交或回滚之前,这些修改对其他事务是可见的。
解决方法: 设置事务隔离级别为READ COMMITTED。
不可重复读(Non-Repeatable Read): 同一个事务在两次查询期间,由于其他事务的修改或删除,导致查询结果不一致。
解决方法: 设置事务隔离级别为REPEATABLE READ。
幻读(Phantom Read): 同一个事务在两次查询期间,由于其他事务的插入操作,导致查询结果集中出现之前不存在的行。
解决方法: 设置事务隔离级别为SERIALIZABLE。
3、数据库的隔离级别
查看隔离级别
- 查看隔离级别,8.0版本之前的,用SELECT @@tx_isolation
select @@transaction_isolation;- 修改隔离级别
set session transaction isolation level READ UNCOMMITTED;
读未提交(READ-UNCOMMITTED):
-
事务可以读取其他事务未提交的数据,这被称为脏读(Dirty Read)。
-
最低的隔离级别,提供了最少的并发控制。
设置隔离级别为读未提交
- 设置隔离级别
set session transaction isolation level read uncommitted;- 查看隔离级别
select @@transaction_isolation;
读已提交(read committed oracle默认的隔离级别)
-
事务只能读取其他事务已经提交的数据,避免了脏读。
-
但是,在同一个事务中,多次读取同一数据可能会得到不同的结果,这被称为不可重复读(Non-Repeatable Read)。
例:事务 A 读取了数据,然后事务 B 修改了该数据并提交。事务 A 再次读取该数据时,得到了不同的结果,这就是不可重复读。
-- 事务 A
START TRANSACTION;
SELECT * FROM table_name; -- 第一次读取
-- 其他操作
SELECT * FROM table_name; -- 第二次读取,可能得到不同的结果
COMMIT;
-- 事务 B
START TRANSACTION;
UPDATE table_name SET column_name = value WHERE condition;
COMMIT;
设置隔离级别为读已提交
- 设置隔离级别
set session transaction isolation level read committed;- 查看隔离级别
select @@transaction_isolation;
可重复读(repeatable read mysql 的默认隔离级别)
-
在同一个事务中,多次读取同一数据时,结果是一致的,避免了不可重复读。
-
但是,可能会出现幻读(Phantom Read)。幻读是指在一个事务中,两次查询返回的行数不同,这是因为其他事务插入或删除了数据。
-
mysql> select @@transaction_isolation;
+-------------------------+
| @@transaction_isolation |
+-------------------------+
| READ-UNCOMMITTED |
+-------------------------+
例:事务 A 读取了一些数据,然后事务 B 插入了一些新的数据。事务 A 再次查询时,发现多了一些数据,这就是幻读。
-- 事务 A
START TRANSACTION;
SELECT * FROM table_name WHERE condition; -- 第一次查询
-- 其他操作
SELECT * FROM table_name WHERE condition; -- 第二次查询,可能出现幻读
COMMIT;
-- 事务 B
START TRANSACTION;
INSERT INTO table_name VALUES (...);
COMMIT;
串行化(Serializable)
-
最高的隔离级别,提供了最强的并发控制。
-
事务之间是完全隔离的,一个事务必须等待另一个事务完成后才能执行。
-
避免了脏读、不可重复读和幻读。
例:事务 A 和事务 B 同时尝试对同一数据进行操作,事务 B 必须等待事务 A 完成后才能执行
-- 事务 A
START TRANSACTION;
SELECT * FROM table_name WHERE condition FOR UPDATE; -- 锁定数据
-- 其他操作
COMMIT;
-- 事务 B
START TRANSACTION;
SELECT * FROM table_name WHERE condition FOR UPDATE; -- 等待事务 A 完成
-- 其他操作
COMMIT;
4、如何选择隔离级别
并发程度:如果系统需要高并发,那么可以选择较低的隔离级别,以提高并发性能。但是,这可能会导致数据的不一致性。
数据一致性要求:如果系统对数据一致性要求很高,那么应该选择较高的隔离级别,以确保数据的正确性。
性能要求:较高的隔离级别通常会导致性能下降,因为需要更多的锁和同步机制。
在实际应用中,可以根据具体情况选择合适的隔离级别。一般来说,读已提交是比较常用的隔离级别,它可以避免脏读,同时提供了较好的并发性能。如果对数据一致性要求非常高,可以选择可重复读或串行化。