概述:事务(Transaction),是数据库操作的最小工作单元,是作为单个逻辑工作单元执行的一系列操作;这些操作作为一个整体一起向系统提交,要么都执行、要么都不执行;事务是一组不可再分割的操作集合。
事务的特征(ACID)又称基本要素:
原子性(Atomicity):将所有 SQL 作为原子工作单元执行,要么全部执行,要么全部不执行 一致性(Consistency):事务完成后,所有数据的状态都是一致的 隔离性(Isolation):如果有多个事务并发执行,每个事务作出的修改必须与其他事务隔离 持久性(Durability):即事务完成后,对数据库数据的修改被持久化存储
?事务并发容易产生的问题:
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当前事务隔离级别,默认为REPEATABLE-READ(可重复读)
mysql> SELECT @@transaction_isolation;
+-------------------------+
| @@transaction_isolation |
+-------------------------+
| REPEATABLE-READ |
+-------------------------+
1 row in set (0.00 sec)
MySQL默认操作模式为自动提交模式
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)
|