事务的四大特性ACID
- 原子性:事务是一个不可分割的工作单位,事务中的操作,要么全部都发生,要么全都不发生
- 一致性:事务前后,数据的完整性,必须要保持一致,举个例子,a给b转账100,需要执行三个步骤,查询a的余额是否足够大于等于100,将a的余额减100,将b的余额加100,那么这三个步骤,必须在一个事务中,不能前两个一个事务,第三步一个事务,因为当前两步的那个事务执行完了,数据库中的钱的总量就跟事务开始之前不一致了,就破坏了事务的一致性,所以在设置这个事务的时候,就必须是三步,不能是分开的,容易跟原子性混淆,一致性强调的是,事务中要不要加上b余额加100这个操作,而原子性是强调这些操作是不是最后都成功或者失败了。一个事务执行之前和执行之后都必须处于一致性状态。拿转账来说,假设用户A和用户B两者的钱加起来一共是5000,那么不管A和B之间如何转账,转几次账,事务结束后两个用户的钱相加起来应该还得是5000,这就是事务的一致性。
- 隔离性:事务之间相互隔离,互不影响
- 持久性:事务结束之后,对数据的修改就是永久性的,就算事务结束后数据库发生故障,也不会对其产生影响。
mysql事务隔离级别
- read uncommited:一个事务中,可以查看到另一个事务中未commit的修改,所以会有脏读问题。
- read commited:一个事务只有commit了之后,所做的修改才能被别的事务看到,所以不会出现脏读问题,但是会出现不可重复读的问题
- repeated read:一个事务中,读取到的某项数据一直是一样的,就算在过程中,有别的事务修改了这项数据并comiit了,但是查询到的一直就是事务开始时的那一刻,这项数据的样子。所以就不会出现不可重读读的问题,也就是因此这个级别的名字才叫做可重复读。这个级别是mysql的默认的事务隔离级别。它的实现原理是MVCC(即Mutil-Version Concurrency Control,多版本并发控制,类似于乐观锁的一种实现方式),也就是说,mysql默认给每行数据都添加了版本字段(两个字段,分别是创建版本,和删除版本),在一个事务中,永远只查询某一个特定版本的数据,也就是在事务开始的时候,这行数据的最新版本,如果在这个时候,另一个事务修改了这个数据,那么相应的版本也会+1,但是不会影响本事务中的查询结果,因为查询的依旧是之前版本的数据,所以就实现了可重复读。一般的数据库中,这个级别是会出现幻读的问题的,但是innodb引擎中,这个级别是不会出现幻读的,如果是当前读,当前读就是加锁的select,update,delete语句,数据库会使用next-key locks来锁住本条记录以及索引区间,所以别的事务,就无法在这个区间中添加新的数据,如果是普通读,就是没有加锁的读,解决幻读的手段是MVVC,也就是只会读当前事务开始时的那个版本号的数据,就算有新的数据插入进来,也是读不到的,所以两次读之间,肯定不会出现幻读问题。
- serializable:完全串行化的读,每次读都需要获得表级共享锁,读写相互都会阻塞,效率很低
下面的表格是对mysql事务隔离级别所会出现的问题的总结
mysql事务隔离级别 | 脏读 | 不可重复读 | 幻读 |
---|---|---|---|
read uncommited | 存在 | 存在 | 存在 |
read commited | 不存在 | 存在 | 存在 |
repeated read | 不存在 | 不存在 | 不存在 |
serializable | 不存在 | 不存在 | 不存在 |