事务
事务的核心是是其原子性,在计算机中我们把不可分割的事物成为具有原子性,而事务就是不可分割的。
我们常常会遇到下面的情况:
A 转账给 B 100元
与之对应的B 会收到 A 的100元
这两件事必须要么全部失败,要么全部完成,是不可分割的,如果转账成功后服务器突然有问题使得B并没有收到100元,这就会造成很大的问题。而事务为这种情况提供了回滚(roll back)的操作,使数据回到转账之前,即保证了数据的“一荣俱荣,一损俱损”。
除了其核心的原子性之外,事务还具有其它三个特性:
- 持久性:即事务进行的改动全部都会存在硬盘中,不会因为服务器关机或重启而改变
- 一致性:即事务进行改变时是从一个一致的状态转为另一个一致的状态,“一致”指的是数据都能对的上
- 隔离性:即并行开发时,事务之间能够保持隔离,互不干扰。
持久性就不再具体叙述。
一致性
依旧是前面转钱的例子,如果A转账成功而B没有收到钱,这就是从一个一致的状态转为一个不一致的状态。我们可以发现原子性和一致性是紧密相连的。
隔离性
隔离性虽然定义简单,但根据其隔离的等级又可深入研究。
-
脏读问题
A和B两人同时处理一个账户,如果A看到账户有100,之后B又给账户中冲了100,这时就发生了脏读问题,即A读到了错误的数据。为避免这种情况数据库软件提供了锁机制,只要让B修改时禁止A读数据就避免了脏读问题,即对写操作上了锁,这样做降低了并发性,但稍微提高了结果的准确性
-
不可重复读问题
同样是A和B,如果A正在读数据,此时B突然修改了数据,这就会导致A读完后想再读一遍时发现数据出现了变化,造成了不可重复 度问题。对于这个问题,我们可以把读操作加锁,即在读数据时禁止写入数据。这样做又降低了并发性,进一步提高了数据的准确性。
-
幻读问题
还是A和B,A在读数据时,B又想添数据,不过B这时想修改或添加的是另一个文件,并不会影响A正在读的数据。这样虽然A多次读数据并没有影响,但会出现读着读着发现多了一个文件的情况,好像出现了幻觉,但在大多数情况下这种情况并没有影响。想要避免幻读问题,就要把并行事务串行化,即A在做的时候B就不能做,反过来也是这样。这种方法使得数据的准确性最大化,而并行化降至最低。
数据库的隔离机制
对于不同的问题,mySQL提供了四种隔离等级:
- read uncommitted 允许读未提交的数据,即完全放行,A想干啥就干啥,B想干啥就干啥,并行程度最高,数据准确性最低
- read committed 只能读提交之后的数据,即给写操作加锁,避免了脏读问题
- repeatable read 给读和写操作加锁,避免了脏读问题和不可重复读问题
- serializable 即串行化,数据的准确性最大化,而并行化降至最低,同时避免脏读、不可重复读和幻读问题。
对于不同场景,我们可根据需要选择不同的等级,例如B站点赞功能就不需要那么高的准确性,完全可以使用最低等级限制,而对于转账问题就要使用较高等级的隔离手段。mySQL默认是第三等级,如果需要修改需要在配置文件中修改。