Mysql的事务详解

数据库事务

提到事务,你肯定不陌生,和数据库打交道的时候,我们总是会用到事务。最经典的例子就是转账,你要给朋友小王转100块钱,而此时你的银行卡只有100块钱。

转账过程具体到程序里会有一系列的操作,比如查询余额、做加减法、更新余额等,这些操作必须保证是一体的,不然等程序查完之后,还没做减法之前,你这100块钱,完全可以借着这个时间差再查一次,然后再给另外一个朋友转账,如果银行这么整,不就乱了么?这时就要用到“事务”这个概念了。

简单来说,事务就是要保证一组数据库操作,要么全部成功,要么全部失败。

在MySQL中,事务支持是在引擎层实现的。你现在知道,MySQL是一个支持多引擎的系统,但并不是所有的引擎都支持事务。比如MySQL原生的MyISAM引擎就不支持事务,这也是MyISAM被InnoDB取代的重要原因之一。

事务隔离级别

  1. 读未提交(READ UNCOMMITTED)

    一个事务还没提交时,它做的变更就能被别的事务看到

    缺点:可能产生脏读、不可重复读、幻读

  2. 读已提交(READ COMMITTED)

    一个事务提交之后,它做的变更才会被其他事务看到

    缺点:避免了脏读,可能产生不可重复读、幻读

  3. 可重复读(REPEATABLE READ)(mysql默认隔离级别)

    一个事务执行过程中看到的数据,总是跟这个事务在启动时看到的数据是一致的。当然在可重复读隔离级别下,未提交变更对其他事务也是不可见的

    避免了脏读,不可重复读。通过区间锁技术避免了幻读

  4. 串行化(SERIALIZABLE)

​ 顾名思义是对于同一行记录,“写”会加“写锁”,“读”会加“读锁”。当出现读写锁冲突的时候,后访问的事务必 须等前一个事务执行完成,才能继续执行

串行化可以避免所有可能出现的并发异常,但是会极大的降低系统的并发处理能力

常见的并发问题

  1. 脏读

    一个事务读取了另一个事务未提交的数据

  2. 不可重复读

    一个事务对同一数据的读取结果前后不一致。两次读取中间被其他事务修改了

  3. 幻读

    幻读是指事务读取某个范围的数据时,因为其他事务的操作导致前后两次读取的结果不一致。幻读和不可重复读的区别在于,不可重复读是针对确定的某一行数据而言,而幻读是针对不确定的多行数据。因而幻读通常出现在带有查询条件的范围查询中

事务的ACID特性

  • 原子性(Atomicity)

    事务中的所有操作作为一个整体像原子一样不可分割,要么全部成功,要么全部失败

  • 一致性(Consistency)

    事务的执行结果必须使数据库从一个一致性状态到另一个一致性状态。一致性状态是指:1.系统的状态满足数据的完整性约束(主码,参照完整性,check约束等) 2.系统的状态反应数据库本应描述的现实世界的真实状态,比如转账前后两个账户的金额总和应该保持不变

  • 隔离性(Isolation)

    并发执行的事务不会相互影响,其对数据库的影响和它们串行执行时一样。比如多个用户同时往一个账户转账,最后账户的结果应该和他们按先后次序转账的结果一样

  • 持久性(Durability)

    事务一旦提交,其对数据库的更新就是持久的。任何事务或系统故障都不会导致数据丢失