3.1、什么是事物
- 事物就是一组原子性的SQL查询,或者一个独立的工作单元。如果数据库引擎能够成功地对数据库应用该组查询的全部语句,那么就执行该组查询。如果其中有任何一条语句因为奔溃或者其他原因无法执行,那么所有的语句都不会执行。也就是说,事物内的语句,要么全部成功,要么全部失败
3.2、ACID
-
1、原子性(Atomicity):事务开始后所有操作,要么全部做完,要么全部不做,不可能停滞在中间环节。事务执行过程中出错,会回滚到事务开始前的状态,所有的操作就像没有发生一样。也就是说事务是一个不可分割的整体,就像化学中学过的原子,是物质构成的基本单位。
-
2、一致性(Consistency):数据库总是从一个一致性的状态转换到另外一个一致性的状态。事务开始前和结束后,数据库的完整性约束没有被破坏 。比如A向B转账,不可能A扣了钱,B却没收到。如果A向B转账中间出了一些异常,那么事物回滚掉,次事物中所在的任何修改都不会保存到数据库中。
-
3、隔离性(Isolation):一个事物所做的修改在最终没有提交以前,其他事物是对其他不可见的。
-
4、持久性(Durability):事务完成后,事务对数据库的所有更新将被永久的保存到数据库。
3.3 隔离级别
- Read uncommitted 读未提交 (可以读没有提交的事物)
公司发工资了,把50000元打到我的账号上,但是该事务并未提交,而我正好去查看账户,发现工资已经到账,是50000元整,非常高兴。可是不幸的是,领导发现发给的工资金额不对,是2000元,于是迅速回滚了事务,修改金额后,将事务提交,最后我实际的工资只有2000元,空欢喜一场。
脏读是两个并发的事务,“事务A:领导发工资”、“事务B:我查询工资账户”,事务B读取了事务A尚未提交的数据。
当隔离级别设置为Read uncommitted时,就可能出现脏读,如何避免脏读,请看下一个隔离级别。
- Read uncommitted 读未提交 (可以读没有提交的事物)
- Read committed 读提交 (读已提交的事物)
我拿着工资卡去消费,系统读取到卡里确实有2000元,而此时老婆也正好在网上转账,把工资卡的2000元转到她账户,并在我之前提交了事务,当我扣款时,系统检查到工资卡已经没有钱,扣款失败,十分纳闷,明明卡里有钱,为何......
不可重复读是两个并发的事务,“事务A:消费”、“事务B:老婆网上转账”,事务A事先读取了数据,事务B紧接了更新了数据,并提交了事务,而事务A再次读取该数据时,数据已经发生了改变。
当隔离级别设置为Read committed时,避免了脏读,但是可能会造成不可重复读。
- Read committed 读提交 (读已提交的事物)
- Repeatable read 重复读
当隔离级别设置为Repeatable read时,可以避免不可重复读。当我拿着工资卡去消费时,一旦系统开始读取工资卡信息(即事务开始),我老婆就不可能对该记录进行修改,也就是不能在此时转账。
虽然Repeatable read避免了不可重复读,但还有可能出现幻读。例如:老婆工作在银行部门,她时常通过银行内部系统查看我的信用卡消费记录。有一天,她正查询到我当月信用卡的总消费金额(select sum(amount) from transaction where month = 本月)为80元,而我此时正好在外面吃完大餐后在收银台买单,消费1000元,即新增了一条1000元的消费记录(insert transaction ... ),并提交了事务,随后老婆将我的当月信用卡消费的明细打印到A4纸上,却发现消费总额为1080元,老婆很诧异,以为出现了幻觉,幻读就这样产生了。
- Repeatable read 重复读
- Serializable (串行化):可避免脏读、不可重复读、幻读的发生。
-
5.重点
- 5.1、事务隔离级别为读提交时,写数据只会锁住相应的行
- 5.2、事务隔离级别为可重复读时,如果检索条件有索引(包括主键索引)的时候,默认加锁方式是next-key 锁;如果检索条件没有索引,更新数据时会锁住整张表。一个间隙被事务加了锁,其他事务是不能在这个间隙插入记录的,这样可以防止幻读。
- 5.3、事务隔离级别为串行化时,读写数据都会锁住整张表
- 5.4、隔离级别越高,越能保证数据的完整性和一致性,但是对并发性能的影响也越大。
- 6.事务的并发问题
- 6.1、脏读:事务A读取了事务B更新的数据,然后B回滚操作,那么A读取到的数据是脏数据
- 6.2、不可重复读:事务 A 多次读取同一数据,事务 B 在事务A多次读取的过程中,对数据作了更新并提交,导致事务A多次读取同一数据时,结果 不一致。
- 6.3、幻读:系统管理员A将数据库中所有学生的成绩从具体分数改为ABCDE等级,但是系统管理员B就在这个时候插入了一条具体分数的记录,当系统管理员A改结束后发现还有一条记录没有改过来,就好像发生了幻觉一样,这就叫幻读。
小结:不可重复读的和幻读很容易混淆,不可重复读侧重于修改,幻读侧重于新增或删除。解决不可重复读的问题只需锁住满足条件的行,解决幻读需要锁表
3.4、死锁 - 死锁是指两个或者多个事物在同一个资源上互相占用,并请求锁定对方占用的资源,从而导致恶性循环的现象。当多个事物试图以不同的顺序锁定资源时,就可能会产生死锁。多个事物同时锁定同一个资源时,也会产生死锁。
事务1:
start transaction;
update stockprice set close = 45.50 where stock_id =4 and date = '2022'
update stockprice set close = 45.50 where stock_id =3 and date = '2022'
commit;
事务2:
start transaction;
update stockprice set close = 45.50 where stock_id =3 and date = '2022'
update stockprice set close = 45.50 where stock_id =4 and date = '2022'
commit;
- 以上代码会出现死锁现象。InnoDB目前处理死锁的方法是,将持有最少行级排他锁的事物进行回滚(这是相对比较简单的死锁回滚算法)
- 死锁发生以后,只有部分或者完全回滚其中一个事物,才能打破死锁。对于事物类型的系统,这是无法避免的,所以应用程序在设计时必须考虑如何处理死锁。大多数情况下只需要重新执行因死锁回滚的事物即可。
网友评论