什么是数据库事务,为啥要有?
事务:由一个有限的数据库操作序列构成,这些操作要么全部执行,要么全部不执行,是一个整体不可分割
假如A转账给B 100 元,先从A的账户里扣除 100 元,再在 B 的账户上加上 100 元。如果扣完A的100元后,还没来得及给B加上,银行系统异常了,最后导致A的余额减少了,B的余额却没有增加。所以就需要事务,将A的钱回滚回去,就是这么简单。
为啥要有?保证数据的最终一致性
事务的特性
四个典型特征:原子性,一致性,隔离性,持久性
原子性:事务作为一个整体被执行,包含在其中的对数据库的操作要么全部执行,要么都不执行。
一致性:几个并行执行的事务,其执行结果必须与按某一顺序 串行执行的结果相一致。假如A账户给B账户转10块钱,不管成功与否,A和B的总金额是不变的。
隔离性:事务的执行不受其他事务的干扰,事务执行的中间结果对其他事务透明。
持久性:事务完成提交后,事务对数据库所作操作更改,持久保存在数据库中
1.脏读(dirty read)
原因:
指事务读取到其他事务未提交的值
例子:事务A/B和一条记录:id=1,name=王五
A修改id=1中的name值为李四,但是还为提交事务
B再A事务未提交时进行查询,查询出来的结果是id=1的数据库中,name的值为李四
然后重点来了
A回滚修改的name的值,现在数据库存的王五,但是B查询出来的却是李四;
这就是脏读,事务B读取了事务A未提交的数据
2.不可重复读(non-repeatable read)
原因:
不可重复读是指再同一次事务中前后查询不一致
例子:事务A查询一条记录,name=王五,事务B执行更新name=李四,并且提交了,A按照相同的条件查询,name=李四,事务A就会出现一个问题,同样查询的语句,两次执行结果不一致
同一事物前后查询不一致
3.幻读(phantom read)
原因:
并发事务的存在导致的。当多个事务同时执行相同查询操作时,如果其中有一个事务进行了插入、更新或删除操作,有可能导致其他事务的查询结果不同
例子:事务A先执行查询,只有一条数据,事务B插入一条数据,A按照相同条件查询,结果多了一条记录
4. 总结
脏读是指事务读取到其他事务正在处理的未提交数据
不可重复读指在并发更新时,另一个事务前后执行相同条件的查询得到的数据不一致
幻读指并发插入、删除时,另一个事务前后执行相同条件的查询得到的数据不一致
5.解决办法
如何解决以上问题,事务的隔离级别就派上用场了
禁止写时读,避免了“脏读”,对应隔离级别read committed。
禁止读时写,避免了“不可重复读”,对应隔离级别repeatable read。
而为了避免“幻读”,干脆把整个表给锁住了,只能是serialize了。
隔离级别越高,并行度越低,付出的代价越大。
MySQL默认事务隔离级别为:可重复读(repeatable-read),因此当我们使用MySQL进行实际开发时一般不会发生“脏读”和“不可重复读”。现在可能遇到的问题就是“幻读”,不过MySQL通过多版本并发控制(MVCC)机制解决了该问题。
6、事务的隔离界别(补充)
读未提交(Read Uncommitted):读的是另一个事务未提交的数据,导致脏读、不可重复读、幻读
读已提交(Read Committed):读取已经提交的数据,还是会造成幻读,不可重复读
可重复读(Repeatable Read): 确保一个事务在多次读取同一数据时,能看到同样的数据行,可以避免脏读和不可重复读,但依旧可能存在幻读
串行化(Serializable): 最高的隔离级别,避免所有的并发问题,但是会降低并发性能
7.数据库是如何保证事务的隔离性的
加锁:例如,你晚上想在屋里安静的刷剧,给房门加把锁,别让别人进来足以
串行化隔离级别就是枷锁实现的,频繁的加锁会降低数据库性能
解决加锁后的性能问题就要了解mvcc多版本并发控制(再写啦)了