什么转账失败了? 那可能是「数据库事务」没有处理好
Posted 程序员阿凯
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了什么转账失败了? 那可能是「数据库事务」没有处理好相关的知识,希望对你有一定的参考价值。
阅读文本大概需要 6 分钟。
中午和同事一起吃饭,饭后AA,可一直没收到同事转账,下班前提醒了她。同事说:早就给你转过去了啊,我的钱都扣了的。可是,你的账户上确实没有收到...
这事可能真不是你的同事想懒你这十几块钱,有可能是遇到数据库事务出了问题...
一个数据库事务通常包含了一个序列的对数据库的读/写操作。它的存在包含有以下两个目的:
为数据库操作序列,提供了一个从失败中恢复到正常状态的方法,同时提供了数据库即使在异常状态下仍能保持一致性的方法。
当多个应用程序在并发访问数据库时,可以在这些应用程序之间提供一个隔离方法,以防止彼此的操作互相干扰。
当事务被提交给了DBMS(数据库管理系统),则DBMS(数据库管理系统)需要确保该事务中的所有操作都成功完成且其结果被永久保存在数据库中,如果事务中有的操作没有成功完成,则事务中的所有操作都需要被回滚,回到事务执行前的状态;同时,该事务对数据库或者其他事务的执行无影响,所有的事务都好像在独立的运行。
老马给老王转1000块钱,这个过程涉及到两个数据库的操作:
1、先是从老马的账上扣除1000;
2、再在老王的账上加上1000。
如果这两次操作是独立的,那么有可能老马扣掉1000块钱之后,服务器异常,老王的帐上没有加上1000。
我们就希望这两次数据库的操作不是相互独立的,即处于同一事务。
数据库中的事务 是指逻辑上的一组操作,这组操作要么都执行成功,要么都不执行成功。
2.1 事务的四大特性(ACID)
事务的四大特性分别是:
l原子性 (Atomicity):事务中所有操作是不可再分割的原子单位。事务中的所有操作要么全部执行成功,要么全部执行失败。
l一致性 (Consistency):事务执行后,数据库状态与其他业务规则保持一致。如转账业务,无论事务是否执行成功,参与转账的两个账号的余额之和应该保持不变。
l隔离性 (Isolation):在并发操作中,不同事务之间应该隔开,使每个并发中的事务不会相互干扰。
l持久性 (Durability):一旦事务提交成功,事务中所有的数据操作都必须持久化到数据库。即使提交事务后,数据库马上崩溃,在数据库重启的时候,也必须能保证通过某种机制恢复数据。
2.2 mysql中开启和关闭事务
默认情况下,mysql每执行一条sql语句,都是一个单独的事务,如果需要在一个事务中包含多条sql语句,那么需要在执行sql之前开启事务.
l 开启事务:start transaction
l 出现异常:rollback ( 回滚 )
l 关闭事务:commit ( 提交 )
在执行sql之前,先执行start transaction,这就开启了一个事务,然后可以去执行多条sql语句,最后要结束事务 commit 表示提交,即事务中的多条 sql 语句所做出的影响会持久化到数据库。或者通过 rollback 回滚,即回到事务起点,之前做的所有操作都将被取消。
以tom给jim转账为例进行演示:
查询所有人的余额
开启事务
tom减去100块钱
查询余额
给jim加上100块钱
再次查询余额
回滚事务
再次查询余额
之前的操作全部取消了...
如果我们不考虑事务的隔离性,当有多个线程在进行数据库操作的时候,会出现一些严重的问题.
3.1 事务的并发读问题
l脏读:读取到另一个事务未提交的数据
l不可重复读:对同一字段的两次读取 数据不一致。因为另一事务对该数据进行了修改(update)
l幻读(虚读):对同一张表的两次查询 记录不一致。因为另一个事务插入( insert )了一条数据
3.2 事务的四大隔离级别
为了防止并发读问题,mysql 有四种隔离级别。在相同的数据环境下,使用相同的输入,执行相同的工作,但隔离级别不同,可以导致不同的结果。
Serializable:串行化
不会出现任何并发问题,因为它对同一数据的访问是串行的,而不是并发访问的.但是这种级别性能最差。
Repeatable Read:可重复读(Mysql 默认隔离基本)
防止脏读和不可重复读,会出现虚读。性能比Serializable好。
Read Committed:读已提交数据(Oracle 默认隔离级别)
防止脏读,性能比Repeatable Read好.
Read Uncommitted:提交未读数据
性能最好,但是所有并发读问题都可能出现。
后台回复” MySQL“ 可以领取 其他更多 MySQL 相关的学习资料。
以上是关于什么转账失败了? 那可能是「数据库事务」没有处理好的主要内容,如果未能解决你的问题,请参考以下文章