什么转账失败了? 那可能是「数据库事务」没有处理好

阅读文本大概需要 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转账为例进行演示:

  1. 查询所有人的余额
  1. 开启事务
  1. tom减去100块钱
  1. 查询余额
  1. 给jim加上100块钱
  1. 再次查询余额
  1. 回滚事务
  1. 再次查询余额

之前的操作全部取消了...

事务的隔离级别

如果我们不考虑事务的隔离性,当有多个线程在进行数据库操作的时候,会出现一些严重的问题.

3.1 事务的并发读问题

l脏读:读取到另一个事务未提交的数据

l不可重复读:对同一字段的两次读取 数据不一致。因为另一事务对该数据进行了修改(update)

l幻读(虚读):对同一张表的两次查询 记录不一致。因为另一个事务插入( insert )了一条数据

3.2 事务的四大隔离级别

为了防止并发读问题,mysql 有四种隔离级别。在相同的数据环境下,使用相同的输入,执行相同的工作,但隔离级别不同,可以导致不同的结果。

  1. Serializable:串行化

不会出现任何并发问题,因为它对同一数据的访问是串行的,而不是并发访问的.但是这种级别性能最差

  1. Repeatable Read:可重复读(Mysql 默认隔离基本)

防止脏读和不可重复读,会出现虚读。性能比Serializable好。

  1. Read Committed:读已提交数据(Oracle 默认隔离级别)

防止脏读,性能比Repeatable Read好.

  1. Read Uncommitted:提交未读数据

原文发布于微信公众号 - 程序员阿凯(AKBC159)

原文发表时间:2018-05-28

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏java初学

linux进程调度

42014
来自专栏大数据架构

Kafka设计解析(八)- Exactly Once语义与事务机制原理

1303
来自专栏Android 研究

Java虚拟机基础——1Java的内存模型

最近和几个之前一起做安卓的朋友喝酒,他最近在研究JVM,我们就简单的讨论了起来,他比我研究的深很多,我也不甘堕落,自己也开始研究了一下,写了4篇文章整理了一下自...

442
来自专栏青枫的专栏

如何判断一个程序是否会有线程安全问题?

791
来自专栏LanceToBigData

MySQL(十三)之MySQL事务

前言   这段时间自己会把之前学的东西都总结一遍,希望对自己以后的工作中有帮助。其实现在每天的状态都是很累的,但是我要坚持!   进入我们今天的正题:   为什...

1766
来自专栏大闲人柴毛毛

数据库事务详解

什么是『事务』? 事务就是一组具有原子性的操作,这一组操作要么全都正确执行,要么全都不执行。 事务能保证数据库从一种一致性状态转换为另一种一致性状态。 事...

4115
来自专栏linux驱动个人学习

Linux内核线程kernel thread详解--Linux进程的管理与调度(十)

Linux内核可以看作一个服务进程(管理软硬件资源,响应用户进程的种种合理以及不合理的请求)。

965
来自专栏HappenLee的技术杂谈

存储与索引------《Designing Data-Intensive Applications》读书笔记3

键值对数据库是数据库形式之中最简单的一种模式,我们可以把它简化的实现为下面两个函数:

812
来自专栏Java架构师进阶

Java四类八种基本数据类型进一步了解Java

Java字符采用Unicode编码,每个字符占两个字节,因而可用16进制编码形式表示

694
来自专栏乐沙弥的世界

MongoDB执行计划获取(db.collection.explain())

923

扫码关注云+社区