前言
大家在生活中肯定使用过微信或者支付宝转账吧,那么大家有没有想过一个问题呢?就是如果你向商家转账了,但是突然微信或者支付宝服务器出现问题了,商家并没有收到转账该怎么办呢?
今天我将来带大家了解解决这一问题的方法:MySQL事务🚗🚗🚗
什么是MySQL事务
MySQL事务是指一组数据库操作,这组操作要么全部成功执行,要么全部回滚到操作前的状态。将一系列操作组合成事务可以确保数据的一致性和完整性。就是因为MySQL的这种特性,我们才能尽可能地避免微信或者支付宝转账未收到的问题。
MySQL事务的基本流程是:
start transaction 开启事务
执行操作
commit 提交事务
数据库事务的四个关键特性
- 原子性(最核心的特性)
- 一致性 事务执行前后,数据是靠谱的
- 持久性 事务修改的内容是写在硬盘上的,持久存在的
- 隔离性 这个隔离性是为了解决“并发”执行事务,引起的问题
原子性保证事务中的操作要么全部执行成功,要么全部失败回滚;一致性保证事务结束后数据库的状态是合法的;隔离性确保各个并发事务相互隔离,相互之间不会影响彼此的操作;持久性保证一旦事务提交,其所做的改变将永久保存在数据库中。
如果并发的这些事务修改的是不同的表/不同的数据,没什么大问题。
但是如果修改的是同一个表/同一个数据 可能会带来一定的问题
并发执行事务可能产生的问题以及解决方法
1.脏读
脏读是指一个事务在读取了另一个未提交事务的数据时,导致读取到了未经验证的、可能是临时的、不一致或无效的数据。脏读可能会导致数据的不一致性和错误的结果。
脏读的发生是由于MySQL支持事务的并发执行,每个事务都有自己的隔离级别来控制事务与其他事务之间的交互。在读未提交的隔离级别下,一个事务可以读取到另一个事务尚未提交的数据。
举个例子,假设有两个事务同时执行以下操作:
事务A:
UPDATE table SET column='Value' WHERE id=1;
事务B:
SELECT * FROM table WHERE id=1;
在事务A执行UPDATE语句时,数据行被修改但还未提交。此时,如果事务B执行SELECT语句并读取到了事务A修改的数据行,就会发生脏读。如果事务A最终回滚了,那么事务B读取到的数据实际上是无效的或不一致的。
脏读可能会引发严重的数据问题,特别是当事务依赖于准确的、一致的数据时。
如何解决脏读问题
使用合适的隔离级别:选择适当的隔离级别来控制事务的并发读取行为。较高的隔离级别(如可重复读或序列化)可以防止脏读,但可能导致并发性能下降。因此,需要根据应用的需求和数据的一致性要求选择合适的隔离级别。
使用事务和锁:将读操作和写操作组合成事务,使用事务来保证读取的数据是一致的。同时,在修改数据时使用适当的锁来避免并发访问问题。通过控制事务的提交和回滚来确保数据的一致性。
使用行级锁:MySQL提供了行级锁的机制,可以在修改数据时只锁定需要修改的行,而不是锁定整个表。这样可以减少锁竞争和并发性问题,提高系统的并发性能。
使用乐观锁或悲观锁:乐观锁是通过使用版本号或时间戳等机制来控制并发访问的,它假设冲突很少发生;而悲观锁则是通过锁定资源以防止其他事务访问,它假设冲突频繁发生。根据应用需求和数据访问模式,选择合适的锁策略。
优化事务和查询:合理设计事务的范围和持续时间,避免长时间的事务占用资源。同时,优化查询语句和索引的使用,减少数据访问冲突和锁竞争。
合理处理异常和回滚:在事务执行过程中,及时处理异常情况,并正确回滚事务。避免出现未捕获的异常或回滚失败导致的脏数据问题。
2.不可重复读
不可重复读是指在一个事务中,多次读取同一数据时,得到的结果不一致的情况。不可重复读是由于并发事务对数据的修改造成的,与脏读类似,但不可重复读更关注的是读取多次同一数据时的一致性。
举个例子,假设有两个事务同时执行以下操作:
事务A:
SELECT * FROM table WHERE id=1;
事务B:
UPDATE table SET column='Value' WHERE id=1;
在事务A第一次执行SELECT语句时,读取到了id为1的数据行。然后,在事务B执行UPDATE语句修改了id为1的数据行的column字段。此时,如果事务A再次执行SELECT语句,就会发现得到的结果与之前的查询结果不一致,产生了不可重复读的现象。
不可重复读可能会导致以下问题:
-
数据的一致性问题:同一个事务内读取到不同的数据版本,可能导致数据的不一致或错误的结果。
-
业务逻辑问题:如果事务在读取数据后进行了基于这些数据的业务逻辑处理(如计算、判断等),如果多次读取的数据不一致,可能导致业务逻辑的错误。
如何解决不可重复读问题
使用合适的隔离级别:较高的隔离级别(如可重复读或序列化)可以防止不可重复读问题。可重复读隔离级别使用一致性视图来读取数据,保证同一个事务内读取到的数据保持一致。
使用行级锁或乐观锁:通过在修改数据时使用行级锁或乐观锁来防止其他事务对数据进行修改。这样可以保证在同一个事务内多次读取的数据一致性。
优化事务的范围和持续时间:尽量缩小事务的范围和持续时间,减少事务执行期间其他事务对数据的修改。这样可以降低发生不可重复读的概率。
合理设计业务逻辑:在事务内进行业务处理时,需要考虑可能出现不可重复读的情况,设计合适的逻辑来处理这种情况。
3.幻读
幻读是在并发事务中的一种现象,其特点是一个事务在读取数据时,另外一个事务插入了新的数据行,导致第一个事务重新读取数据时,发现多了一些之前不存在的数据行(幻行)。
幻读的出现是由于事务隔离级别的存在,MySQL支持多种事务隔离级别,包括读未提交、读提交、可重复读和串行化。在默认的可重复读隔离级别下,幻读是可能发生的。
当一个事务开始时,MySQL会对查询结果集中的数据行进行加锁,以保证事务的隔离性。在可重复读隔离级别下,MySQL使用共享锁防止其他事务对数据行进行修改,而在事务结束时才释放锁。但是,共享锁只能保证数据行不被删除或修改,却无法防止数据行的插入。因此,在一个事务中,如果先后执行了两个相同的查询语句,第一次查询获取的结果集和第二次查询获取的结果集可能不一样,就会出现幻读的问题。
举个例子,假设有两个事务同时执行以下操作:
事务A:
SELECT * FROM table WHERE column=1;
事务B:
INSERT INTO table (column) VALUES (1);
首先,事务A读取到了满足条件的数据行,而此时事务B插入了一个新的数据行,使得事务A重新读取数据时发现存在一个之前不存在的数据行,这就是幻读的典型情况。
如何解决幻读问题
使用合适的隔离级别:较高的隔离级别(如可重复读或序列化)可以防止幻读问题。可重复读隔离级别使用一致性视图来读取数据,保证在同一个事务内多次执行的查询结果集一致。
使用锁或乐观锁:通过在事务中使用行级锁或乐观锁来防止其他事务对数据进行插入或删除。这样可以保证在同一个事务内多次执行的查询结果集一致。
使用范围锁或间隙锁:范围锁和间隙锁可以在读取数据时锁定一定范围的数据,防止其他事务对该范围内的数据进行插入或删除。
优化事务的范围和持续时间:尽量缩小事务的范围和持续时间,减少事务执行期间其他事务对数据的插入或删除。这样可以降低发生幻读的概率。
合理设计业务逻辑:在事务内进行业务处理时,需要考虑可能出现幻读的情况,设计合适的逻辑来处理这种情况。
在读加锁和写加锁的前提下,数据库使用“串行化”这样的方式来解决幻读,彻底放弃并发处理事务,一个接一个的串行的处理事务。这样做,并发程度是最低的(效率最慢的),隔离性是最高的(数据准确性也是最高的)