发布时间:2024-09-13 13:01
概述:事务(Transaction),是数据库操作的最小工作单元,是作为单个逻辑工作单元执行的一系列操作;这些操作作为一个整体一起向系统提交,要么都执行、要么都不执行;事务是一组不可再分割的操作集合。
事务的特征(ACID)又称基本要素:
原子性(Atomicity):将所有 SQL 作为原子工作单元执行,要么全部执行,要么全部不执行
一致性(Consistency):事务完成后,所有数据的状态都是一致的
隔离性(Isolation):如果有多个事务并发执行,每个事务作出的修改必须与其他事务隔离
持久性(Durability):即事务完成后,对数据库数据的修改被持久化存储
事务原理:
实现事务采取了哪些技术以及思想?主要使用日志和锁
1.原子性:使用 undo log ,从而达到回滚
2.持久性:使用 redo log,从而达到故障后恢复
3.隔离性:使用锁以及MVCC,运用的优化思想有读写分离,读读并行,读写并行
4.一致性:通过回滚,以及恢复,和在并发环境下的隔离做到一致性。
事务并发容易产生的问题:
1、脏读:事务A读取了事务B更新的数据,然后B回滚操作,那么A读取到的数据是脏数据
2、不可重复读:事务 A 多次读取同一数据,事务 B 在事务A多次读取的过程中,对数据作了更新并提交,导致事务A多次读取同一数据时,结果 不一致。
3、幻读:系统管理员A将数据库中所有学生的成绩从具体分数改为ABCDE等级,但是系统管理员B就在这个时候插入了一条具体分数的记录,当系统管理员A改结束后发现还有一条记录没有改过来,就好像发生了幻觉一样,这就叫幻读。
小结:不可重复读的和幻读很容易混淆,不可重复读侧重于修改,幻读侧重于新增或删除。解决不可重复读的问题只需锁住满足条件的行,解决幻读需要锁表
解决方案:
1.针对脏读、不可重复读、幻读,都可设置共享锁(lock in share mode)或者排他锁(for update,行锁)进行限制,保证数据使用过程中的真实性;行锁无法解决幻读,需要表锁。
2.针对不可重复读还可以通过mysql的默认事务隔离机制或者设置事务隔离级别为REPEATABLE_READ(可重复读)。
lock in share mode 就是共享锁
如果事务对某行数据加上共享锁之后,可进行读写操作;其他事务可以对该数据加共享锁,但不能加排他锁,且只能读数据,不能修改数据。 某个事物想进行修改数据操作,那他必须等其他事物的共享锁都释放完毕才能进行修改操作for update 排他锁,就是行锁
如果事务对数据加上排他锁之后,则其他事务不能对该数据加任何的锁。获取排他锁的事务既能读取数据,也能修改数据。注:普通 select 语句默认不加锁,而CUD操作默认加排他锁。
事务隔离级别:
事务隔离级别 | 脏读 | 不可重复读 | 幻读 |
读未提交(read-uncommitted) | 是 | 是 | 是 |
不可重复读(read-committed) | 否 | 是 | 是 |
可重复读(repeatable-read) | 否 | 否 | 是 |
串行化(serializable) | 否 | 否 | 否 |
mysql默认事务隔离级别为可重复读(repeatable-read),但是会有幻读的风险
Oracle默认事务隔离级别为不可重复读(read-committed)
串行化读(serializable)隔离机制最高,性能很低,一般很少用
(串行化:事务在读操作时,先加表级别的共享锁,直到事务结束才释放
事务在写操作时,先加表级别的排它锁,直到事务结束才释放
串行化锁定了整张表,幻读不存在的!!!)
RR级别(repeatable-read)下如何解决幻读:
多版本并发控制(MVCC)+间隙锁(LOCK IN SHARE MODE)解决了幻读的问题
mysql> SELECT @@transaction_isolation;
+-------------------------+
| @@transaction_isolation |
+-------------------------+
| REPEATABLE-READ |
+-------------------------+
1 row in set (0.00 sec)
mysql> select @@autocommit;
ERROR 2006 (HY000): MySQL server has gone away
No connection. Trying to reconnect...
Connection id: 7839
Current database: db
+--------------+
| @@autocommit |
+--------------+
| 1 |
+--------------+
1 row in set (0.13 sec)