事务简介
事务 是一组操作的集合,它是一个不可分割的工作单位,事务会把所有的操作作为一个整体一起向系统提交或撤销操作请求,即这些操作 要么同时成功,要么同时失败。
默认MySQL的事务是自动提交的,也就是说,当执行一条DML语句,MySQL会立即隐式的提交事务。
事务操作
方式一:修改事务的提交方式
- 查看/设置事务提交方式
SELECT @@autocommit;
SET @@autocommit = 0; -- 将事务提交方式改为手动提交;1-自动提交(默认)
- 提交事务
COMMIT;
- 回滚事务
ROLLBACK;
方式二:开启事务
- 开启事务
START TRANSACTION 或 BEGIN;
- 提交事务
COMMIT;
- 回滚事务
ROLLBACK;
事务的四大特性ACID
- 原子性 (Atomicity):事务是不可分割的最小操作单元,要么全部成功,要么全部失败。
- 一致性 (Consistency):事务完成时,必须使所有的数据都保持一致状态。
- 隔离性 (lsolation):数据库系统提供的隔离机制,保证事务在不受外部并发操作影响的独立环境下运行。
- 持久性 (Durability):事务一旦提交或回滚,它对数据库中的数据的改变就是永久的。
并发事务问题
问题 | 描述 |
---|---|
脏读 | 一个事务读到另外一个事务还没有提交的数据。 |
不可重复读 | 一个事务先后读取同一条记录,但两次读取的数据不同,称之为不可重复读。 |
幻读 | 一个事务按照条件查询数据时,没有对应的数据行,但是在插入数据时,又发现这行数据已经存在,好像出现了“幻影” |
脏读
一个事务读到另外一个事务还 没有提交 的数据。
- 事务A的第一个操作查询(SELECT)了一个 id=1 的数据;
- 事务A的第二个操作更新(UPDATE)了 id=1 的数据;
- 此时事务A还未执行完操作并提交事务,然后事务B进来了;
- 事务B执行了查询 id=1 的数据;
- 此后如果事务A因为某种原因撤销对该值的修改,这就导致了事务B所读取到的数据是无效的
不可重复读
一个事务先后读取同一条记录,但两次读取的数据不同,称之为不可重复读。
- 事务A先执行了查询(SELECT) id=1 的数据;
- 此时事务B的执行了一个更新(UPDATE) id=1 的数据的操作,且已经提交到数据库(数据库中前后数据不一致了);
- 此时事务A还未执行完操作并提交事务,然后事务B进来了;
- 事务B执行了查询 id=1 的数据;
- 此后如果事务A因为某种原因撤销对该值的修改,这就导致了事务B所读取到的数据是无效的
幻读
幻读是不可重复读的一种特殊场最。一个事务按照条件查询数据时,没有对应的数据行,但是在插入数据时,又发现这行数据已经存在,好像出现了“幻影”
- 事务A的第一个操作先执行了查询(SELECT) id=1 的数据,发现没有该数据;
- 此时事务B的执行了一个插入(INSERT) id=1 的数据的操作,且已经提交到数据库;
- 然后事务A执行第二个操作插入(INSERT) id=1 的数据,由于id主键的唯一性,所以运行这条插入语句时会报错(数据库中已存在id=1的数据了);
- 事务A执行第三个操作查询(SELECT) id=1 的数据时,因为前面的不可重复读的概念,所以再次查询的时候id=1的数据是一定没有的;
- 此时“幻影”就出现了,明明插入了呀?怎么查不到呢?
事务隔离级别
脏读、不可重复读和幻读这三种异常情况,是在 SQL-92 标准中定义的,同时 SQL-92 标准还定义了 4 种隔离级别来解决这些异常情况,从高到底依次为:顺序执行(Serializable)、可重复读(Repeatable reads)、提交读(Read committed)、未提交读(Read uncommitted)。
隔离级别 | 脏读 | 不可重复读 | 幻读 |
---|---|---|---|
未提交读(Read uncommitted) | √ | √ | √ |
提交读(Read committed) | × | √ | √ |
可重复读(Repeatable reads)-默认 | × | × | √ |
串行化(Serializable) | × | × | × |
注:Oracle的默认事务隔离级别是 提交读(Read committed)
未提交读(Read uncommitted)
未提交读(Read uncommitted)是最低的隔离级别。通过名字我们就可以知道,在这种事务隔离级别下,一个事务可以读到另外一个事务未提交的数据。这种隔离级别下会存在幻读、不可重复读和脏读的问题。
提交读(Read committed)
提交读(Read committed)也可以翻译成读已提交,通过名字也可以分析出,在一个事务修改数据过程中,如果事务还没提交,其他事务不能读该数据。所以,这种隔离级别是可以避免脏读的发生的。
可重复读(Repeatable reads)
可重复读(Repeatable reads),由于提交读隔离级别会产生不可重复读的读现象。所以,比提交读更高一个级别的隔离级别就可以解决不可重复读的问题。这种隔离级别就叫可重复读。但是这种隔离级别没办法彻底解决幻读。
可串行化(Serializable)
可串行化(Serializable)是最高的隔离级别,前面提到的所有的隔离级别都无法解决的幻读,在可串行化的隔离级别中可以解决。
查看事务隔离级别
-- 查看事务隔离级别
SELECT @@TRANSACTION_ISOLATION;
设置事务隔离级别
-- 设置事务隔离级别
SET [SESSION | GLOBAL] TRANSACTION ISOLATION LEVEL {READ UNCOMMITTED | READ COMMITTED | REPEATABLE READ | SERIALIZABLE}
-- SESSION: 只对当前会话(连接)有效,仅对当前客户端窗口有效
-- GLOBAL: 设置全局默认隔离级别,不影响当前已存在的会话,针对于所有客户端的窗口有效
注意:事务隔离级别越高,数据越安全,但是性能越低。