MySQL的事务:当执行一次或者一组SQL语句操作,要么全成功要么全失败,也即是原子操作;
MySQL的是事务是由innodb引擎提供的,我们常见的 InnoDB 引擎它是支持事务的。
不过并不是所有的引擎都能支持事务,比如 MySQL 原生的 MyISAM 引擎就不支持事务,也正是这样,所以大多数 MySQL 的引擎都是用 InnoDB。
随便提一下Innodb的三个特点:
支持事务,支持外键,支持更细粒度的行级锁。
一定谨记这三个特点!!!
事务看起来感觉简单,但是要实现事务必须要遵守 4 个特性,分别如下:
- 原子性(Atomicity):一个事务中的所有操作,要么全部完成,要么全部不完成,不会结束在中间某个环节,而且事务在执行过程中发生错误,会被回滚到事务开始前的状态,就像这个事务从来没有执行过一样;
- 一致性(Consistency):数据库的完整性不会因为事务的执行而受到破坏,比如表中有一个字段为姓名,它有唯一约束,也就是表中姓名不能重复,如果一个事务对姓名字段进行了修改,但是在事务提交后,表中的姓名变得非唯一性了,这就破坏了事务的一致性要求,这时数据库就要撤销该事务,返回初始化的状态。
- 隔离性(Isolation):数据库允许多个并发事务同时对其数据进行读写和修改的能力,隔离性可以防止多个事务并发执行时由于交叉执行而导致数据的不一致。
- 持久性(Durability):事务处理结束后,对数据的修改就是永久的,即便系统故障也不会丢失。
InnoDB 引擎通过什么技术来保证事务的这四个特性的呢?
- 持久性是通过 redo log (重做日志)来保证的;
- 原子性是通过 undo log(回滚日志) 来保证的;
- 隔离性是通过 MVCC(多版本并发控制) 或锁机制来保证的;
- 一致性则是通过持久性+原子性+隔离性来保证;
数据库的隔离级别:
SQL 标准提出了四种隔离级别来规避这些现象,隔离级别越高,性能效率就越低,这四个隔离级别如下:
- 读未提交(read uncommitted),指一个事务还没提交时,它做的变更就能被其他事务看到;
- 读提交(read committed),指一个事务提交之后,它做的变更才能被其他事务看到;
- 可重复读(repeatable read),指一个事务执行过程中看到的数据,一直跟这个事务启动时看到的数据是一致的,MySQL InnoDB 引擎的默认隔离级别;
- 串行化(serializable );会对记录加上读写锁,在多个事务对这条记录进行读写操作时,如果发生了读写冲突的时候,后访问的事务必须等前一个事务执行完成,才能继续执行;
MySQL在并发事务处理时会产生一些问题。
在同时处理多个事务的时候,就可能出现脏读(dirty read)、不可重复读(non-repeatable read)、幻读(phantom read)的问题。
- 脏读:读到其他事务未提交的数据;这种一般都是发生在数据库在读未提交的隔离级别上的情况,由于这个隔离级别太低了所导致的。
- 不可重复读:前后读取的数据不一致;这种一般都是发生在数据库在读以提交的隔离级别上并解决了脏读的问题。
- 幻读:前后读取的记录数量不一致。这种是在数据库在可重复读的隔离级别上并解决了不可重复读的问题上所发生的的。不过根据实验测试幻读这种情况一般是很少出现,通过是发生在大量的事务同时在读取这间操作后并提交事务。
在实际生产中如果操作数据不要求性能要求安全的情况下可以尝试串行化的隔离级别,如果要求性能不要求安全的话,就可以尝试更低级别的隔离级别,当然在想保证安全和性能的情况下最好就是选择可重复读。