事务诞生的目的就是把若干个独立的操作打包成一个整体
四个基本的特性:
1、原子性:要么全都执行成功,要么一个也不执行
事例:A->B转500
A有1000,B有1000,A给B转500,本来A变为500,B变为1500,可是在转账过程中,就可能会出现问题。考虑一个极端情况,执行完第一个SQL 之后,在执行第二个SQL 之前,数据库崩了,A现在变成500,B还是1000,500没给B转过来,事务的原子性就是避免这种中间状态,不让这500丢失。
执行机制:当出现执行失败之后,数据库会自动进行还原操作,把之前改动的数据还原回去
数据库是如何知道该还原成哪个值的呢 ?
数据库会拿个小本子,把执行的每个操作都给记录下来,整个记录的过程搭配了日志+数据库内置的一些表来完成的
2、一致性:
在事务执行之前和执行之后,数据库中的数据都得是合理合法的
例如你转账完之后,不能够出现这种账户为负数的情况
3、持久性
事务一旦提交之后,数据就持久化存储起来了,数据就写入到硬盘
4、隔离性
隔离性描述的是,事务并发执行时候,产生的情况,当并发执行多个事务,尤其是这多个事务尝试修改/读取同一份数据,这个时候就容易出现一些情况,事务的隔离性就是解决这个问题
并发执行可能带来的问题
事例:我在写代码,有一个同学偷瞄了我的屏幕,他看到了我写的代码,看完之后,他就走了,然后我把代码改了,他不知道。
1、脏读问题:
事务A 在对某个数据进行修改,修改的同时,事务B 去读取了这个数据,此时事务B 读到的很可能是一个“脏数据”(这个数据是一个临时的结果,而不是最终的结果)。
出现脏读的问题,原因就是事务和事务之间,没有进行任何的隔离,加上一些约束限制,就可以有效地避免脏读问题。
处理脏读:给写操作加锁,在写的过程中别人不能读了(加锁的状态),等修改完了之后,别人才能 读(解除加锁)
我和同学约定好,你不要看我写的,我写好之后,我提交到码云上,你看我码云上的代码,码云上就是我修改完的代码,这样读到的就不再是中间的数据。
一旦加了这个写锁之后,意味着事务之间的隔离性就高了,并发性就降低了
2、不可重复读:在一个事务中,包含了多次的读操作,这多次的读操作读出来的结果 不一致
我写完代码提交到了码云上,同学在码云上看我写的代码,他看的时候我又写了代码提交了上去
按照针对脏读问题的约束,给写操作进行了加锁,同学要等到我提交之后才能开始读,约定的是写的过程不能读,没说读的过程 。
刚才这个问题就好比说,有个同学在通过码云读代码,随便刷新一下,发现代码变了,(又得重新理解),为了解决这个问题,咱们在做一个约定,之前约定的是,你修改的时候我不能读,现在在约定一下,我读的时候,你也别修改 ,给读操作也加锁了。意味着我必须的等到同学把代码读完了,才能进行修改。通过给读操作也加锁,就解决了不可重读的问题。事务之间的并发性又降低了,隔离性又提高了,并发性和隔离性二者不可兼得。
3、幻读问题: 一个事务执行过程中进行多次查询,多次查询的结果集不一样(多了一 条或者少了一条)
解决幻读问题:彻底串行化执行
同学和我说了,我读代码的时候,你不要写任何代码了
隔离性最高,并发性最低,数据最可靠,速度最慢,并发(快)和隔离(准)是不能兼得的
就可以根据实际需求来调整数据库的隔离级别,通过不同的隔离级别,也就控制了事务之间的隔离性,也就控制了并发程度
MySQl中事务的隔离级别,提供了这么几种:
read uncommitted: 允许读取未提交的数据,并发程度最高,隔离程度最低,会引入脏读+不可复 读+幻读
read committed: 只允许读取提交之后的数据,相当于加锁,并发程度降低了一些,隔离程度提高 了一些,解决了脏读,会引入不可复读+幻读
repeatable read: 相当于给读和写都加锁,并发程度又降低了一些,隔离程度又提高了一些,解决 了脏读和不可复读,引入幻读
serializable: 串行化,并发程度最低(串行执行),隔离程度最高,解决了脏读、不可复读、幻 读,但是执行速度最慢
就可以通过修改my.ini 这个配置文件,来设置当前的隔离级别,根据实际需求场景,来决定使用那种隔离级别。