作者:~小明学编程
文章专栏:MySQL
格言:目之所及皆为回忆,心之所想皆为过往
目录
什么是事务?
事务的特性
原子性
一致性
持久性
独立性
事务之间的影响
脏读
不可重复读
幻读
数据库的隔离级别
读未提交
读已提交
可重复读
可序列化
什么是事务?
数据库中的事务指的是逻辑上的一组数据库的操作要么全部都执行要么都不执行
例如:我们现在要进行一个转账的操作张三要转100元到李四的账户上面去,首先要执行第一条的操作就是先去张三的账户上面-100,然后再在李四的账户上面+100,这两个操作一起称作一条事务,但是在张三账户-100元之后,发生了某些故障导致李四的账户上面没有加上100,这时候我们撤销-100的那条指令,这就是所谓的全部都执行要么全部都不执行。
事务的特性
事务有四大特性,分别是原子性,一致性,持久性,隔离性。
原子性
原子性意味着我们的事务是执行过程中的最小的个体,是不能再被拆分的,一个事务不可能存在只执行了一半的这种情况,要么都执行要么就都不执行
一致性
我们事务在执行完之后必须要确保从一个正确的状态转移到另外一个正确的状态,例如我们用微信支付的时候一件商品100元而我们微信里面只有10元,不可能说是我们支付完之后还剩-90元,这是不正确的状态。
持久性
持久性的意思是我们一个事务提交以后对数据库中数据的的改变是持久的,接下来的其它操作或故障不应该对其执行结果有任何影响。
独立性
并发访问数据库时,一个用户的事务不被其他事务所干扰,各并发事务之间数据库是独立的。
事务之间的影响
脏读
例如我们在进行多人在线编辑的时候,刚开始在输入年龄的时候不小心在20后面多加了一个0就是200,然后这个200就被人读到了,然后我们发现了错误又把200改成了20,这个时候那个人又发现你把刚刚的200怎么变成了20,这就是脏读,因为我们还没有提交,文档里面的数据可变我们读到的只是一个过程数据。
当事务 T1 正在访问字段 A 并且对进行了修改,而这种修改还没有提交到数据库中。这时另外一个事务 T2 也访问和使用字段 A,但由于事务 T1 修改字段 A 后还没有提交 COMMIT
,而那么事务 T2 读到的字段 A 是脏数据。
我们想要解决这个问题的话就在我们写的过程加上锁,这样就不会读到脏数据了。
不可重复读
前面说到我们在写的时候如果去度的话就会读到脏数据,现在我们写的时候不去读了,而是在我们读的时候去写,比如说我们现在有100元,然后有人一定盯着剩余的钱看着,我们买一杯10元的奶茶还剩90,他现在知道我们还剩90,然后做个记录,还剩90,这时候我们又去买了个20的汉堡还剩70,这是那个人打算拿你那个90加上自己的100元190刚好可以买条裤子,但是他再去读的时候发现就剩70了和刚刚读的不一样了。
不可重复读取是指同一个事务在整个事务过程中对同一笔数据进行读取,每次读取结果都不同。如果事务1在事务2的更新操作之前读取一次数据,在事务2的更新操作之后再读取同一笔数据一次,两次结果是不同的。
解决办法就是我们在读的时候给加上锁,读a的时候a不能再改变了。
幻读
前面说到我们在读的时候不能对读的那个事务进行写了,那么现在还有一个问题,既然不能对当前的事务去写我们可以对其它的事务进行写呀。
在同一个事务中,同一个查询多次返回的结果不一致。事务A新增了一条记录,事务B在事务A提交前后各执行了一次查询操作,发现后一次比前一次多了一条记录, 就好像发生了幻觉一样。
要想解决幻读的问题就只能串行的处理事务。
数据库的隔离级别
针对以上的问题我们数据库专门指定相应的隔离来避免这些问题的产生:
共享锁(S锁):假设事务T1对数据A加上共享锁,那么事务T2可以读数据A,不能修改数据A。
排他锁(X锁):假假设事务T1对数据A加上共享锁,那么事务T2不能读数据A,不能修改数据A。
读未提交
Read Uncommitted:最低的隔离级别,什么都不需要做,一个事务可以读到另一个事务未提交的结果。所有的并发事务问题都会发生。
会产生脏读,不可重复读和幻读问题。
读已提交
Read Committed:只有在事务提交后,其更新结果才会被其他事务看见。
我们在写的时候不能读,但是读的时候可以写,可以解决脏读的问题。
可重复读
Repeated Read:在一个事务中,对于同一份数据的读取结果总是相同的,无论是否有其他事务对这份数据进行操作,以及这个事务是否提交。
我们在读一个事务的时候不能写,写的时候也不能读,可以解决脏读和不可重复读的问题。
可序列化
Serialization:事务串行化执行,隔离级别最高,牺牲了系统的并发性。
可以解决脏读,不可重复读,幻读的问题。