1.为什么需要事务
首先我们要知道什么是事务:事务(Transaction)是数据库系统中执行的一个工作单位,它是由用户定义的一组操作序列。一个事务可以是一组SQL语句、一条SQL语句或整个程序,一个应用程序可以包括多个事务。
通俗易懂来说就是,我们在执行一个操作时,要保证要么都成功,要么都不成功。一个比较经典的案例就是:比如我们在发起转账时,A转给B1000元,这个操作其实至少要分为两步:1.A账户余额减少1000,2.B账户增加1000 ,如何保证呢,那就得用到事务的特性(要么1,2都成功,要么1,2都不成功),保证最终数据一致。那么具体怎么实现,我们接下来详细介绍:
2.事务特性
事务具有四大属性:原子性,一致性,持久性,隔离性,下面分别介绍一下四大属性的含义:
原子性:原子性是指一个操作或一组操作要么全部执行成功,要么全部不执行,不会出现部分执行的情况。就像上面的案例,A扣了1000元和B加了1000元,要么都成功,要么都失败。原子性一定程度上保证了数据的一致性。原子性不仅在事务中占有很重要的地位,我们在学习并发编程的时候,会认识到原子性的重要性。
一致性:事务一致性是指事务将数据库从一种一致性转换到另外一种一致性状态,在事务开始之前和事务结束之后数据库中数据的完整性没有被破坏。你发现其实和原子性是比较类似的,一致性更侧重于数据层面的约束,原子性更侧重于操作层面的约束,两者结合其实基本可以满足事务的要求,但对于数据库来说还不够。
持久性:持久性确保一旦事务被提交,其结果将永久保存在数据库中,即使发生系统故障或重启,也不会丢失。
隔离性:一个事务的执行不能被其他事务干扰。即一个事务内部的操作及使用的数据对并发的其他事务是隔离的,并发执行的各个事务之间不能互相干扰。
对于持久性和隔离性来说,更多算是对于事务实现的补充,但反而,我们要付出的代价更大。(ps:我其实在平时的程序设计及代码编写过程中很喜欢这个词,任何需要我为止付出性能上的牺牲,工作量的牺牲,我都称之为代价,我喜欢超前思考,但从不主动设计复杂程序,我更主张写出让人看得懂的“很low“的代码,流畅运行的代码,如果没有说服我的理由,我不会付出代价,带来的好处就是上线问题少很多)。其实在程序设计中也是如此,我们可能就是为了保证那极少数人的变态操作才会将程序设计的如此复杂。以前的时候我很喜欢扣这些细节,然后死磕如何使用代码去“优雅的”解决这些变态问题,慢慢的我会使用一些业务手段规避,其实也就是代价考量的问题。扯远了,接着说回事务:
3.事务并发的一些问题以及如何解决:
理想化的事务执行肯定是排队,但是排队的话效率太慢了,我们又想要事务之间有一定的隔离性,但又想能快点执行,会怎么样呢?或者换个角度问:当我们舍弃一单的隔离性后,会出现什么样的问题呢:
1.脏读:一个事务读到另一个事务的尚未提交的数据
2.不可重复读:事务连续检索两次相同记录的数据,读到的值不一样
3.幻读; 事务A重复执行select(条件相同)语句时,查到了新的记录
幻读和不可重复读都是读到数据变化了,但不可重复读侧重于已读到过的数据发生了变化(比如值变大变小,数据被删除),而幻读侧重于读到了之前没有的记录。
好,知道了会出现的问题,那么怎么解决呢: 通过事务隔离级别。
接下里我们就详细介绍一下事务隔离级别:
事务隔离级别分为以下四种:
READ UNCOMMITTED:未提交读。其实基本没啥限制,可以读到其他事务未提交的数据。所以没啥隔离性,一个问题都没解决。
READ COMMITTED:已提交读。相较未提交读,读不到未提交的数据,但可以读到其他事务已提交的数据,所以还是可能会有不可重复读的问题
REPEATABLE READ:可重复读。事务提交前不会读到当前事务之后提交的事务的数据,这个后面详细介绍,涉及到MVCC以及如何解决不可重复读、幻读问题。
SERIALIZABLE:可串行化。其实就是串行化执行了,可想而知,互联网环境下基本都不会用到。
这篇我们主要了解了一下事务是什么,用来做什么,事务的特性以及常规会出现的问题及对这些问题的处理。下一篇我们聊聊mysql对事务的实现以及解决这些问题的实现原理。
标签:事务,系列,隔离,要么,提交,mysql,一致性,数据 From: https://www.cnblogs.com/gmt-hao/p/18347925