数据库事务管理

在日常的软件开发中除了需要考虑软件性能指标外,还需要特别考虑的地方就是软件的安全性了,提到安全性,那我们就不得不考虑事务管理。也就是在同一个事务下,对数据库的操作要么全成功提交,只要有一个失败,那么已经更新的数据也必须回滚。在spring中使用事务比较简单,因为spring中不但提供了和底层事务无关的事务对象,还提供了声明性事务的功能,目的是让程序从事务代码中解耦,方便我们随时随地的添加事务。

在介绍spring事务之前,我们先简单了解一下数据库事务的知识,说的简单点就是多条SQL语句在执行时,要么全部执行成功,要么全部执行失败。数据库事务包括四个特性:

原子性:表示组成一个事务的多个数据库操作是一个不可分割的原子单元,只有所有的操作执行成功,整个事务才提交,事务中任何一个数据库操作失败,已经执行的任何操作都必须回滚。

一致性:事务操作成功后,数据库所处的状态和它的业务规则是一致的,即数据不会被破坏。说的简单点就是如果从A账户转账到B账户,不管操作成功与否,A和B的存款总额是不会变的。

隔离性:在并发时,不同事务有自己的数据空间,它们的操作不会对对方产生任何干扰。但这不是绝对的,因为数据库中规定了很多种事务的隔离级别,不同的隔离级别对应不同的干扰程度,隔离级别越高,数据一致性越好,但并发性越弱。

持久性:一旦事务提交成功后,事务中所有的数据操作都必须被持久化到数据库中,哪怕数据库崩溃,在数据库重启时,也必须能够保证通过某种机制恢复已经提交过事务数据。

上面的4种特性目的都是一个就是保证数据库的事物安全,那么在数据库的底层是怎么实现上述特性的呢?

实现的方式和Java有些类似,我们知道在Java中是通过对象锁的方式来保证线程安全的,那么同样数据库也是采用锁的方式来实现的。只是这种锁叫做数据库锁。当多个事务试图对相同的数据进行操作时,只有获得到数据库锁的事务才能操作数据,只有当这个事务提交完成后,后面的事务才可以对这个数据进行操作。

在数据库事物中,如果有多个客户端同时访问数据库,也就是并发时数据库中的数据可能会被多个事务同时访问,这时如果没有采取数据库隔离措施,就会导致出现各种并发问题,从而破坏了数据的完整性。我们下面看一下,在这种情况下都会出同哪些问题:

脏读:A事务读取B事务尚未提交的更改数据,并在这个数据的基础上做操作。这时当B事务发生回滚操作时,那么A事务读取到的数据根本就不是最新的。发生这种情况最典型的问题就是取款事务和转账事务并发时就会发生脏读问题。

不可重复读:如果A事务读取了B事务已经提交的数据。但A在取款事务的过程中B又向账户中取出了100元,这时就会导致A两次读取账户的余额不一致。

幻象读:A事务读取B事务提交的新增数据,这时A事务就会出现幻象读的问题。常出现的场景是假设银行系统在同一个事务中,两次统计存款账户的总金额,在两次统计的过程中,刚好往这个账户中新增了100元存款,这时,两次统计的总金额就会不一致。

幻象读和不可重复读是两个不同的概念,前者是指已经读到了其它已经提交的事务的新增数据,而后者是指读到了已经提交事务的更改数据或删除数据。两种不同场景,采取的策略也是不同的,防止读取到更改的数据,只需要对操作的数据添加行级锁即可,这样就可阻止操作中的数据发生变化,而防止读取到新增数据,则往往要添加表级锁,也就是将整个表锁定,以防止新增数据。

丢失更新一:A事务撤消时,把已经提交的B事务的更新数据覆盖了。

余额恢复为1000元(丢失更新)丢失更新二:A事务覆盖B事务已经提交的数据,造成B事务所做的操作丢失。

  • 发表于:
  • 原文链接https://kuaibao.qq.com/s/20190910A05QYS00?refer=cp_1026
  • 腾讯「云+社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。

同媒体快讯

扫码关注云+社区

领取腾讯云代金券