数据库的事务与锁

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/zhchs2012/article/details/79754997

一、什么是事务

事务(Transaction),在计算机术语中是指访问并可能更新数据库中各种数据项的一个程序执行单元(unit)。
一个数据库事务通常包含对数据库进行读或写的一个操作序列。它的存在包含有以下两个目的:
1. 可恢复:为数据库操作提供了一个从失败中恢复到正常状态的方法,同时提供了数据库即使在异常状态下仍能保持一致性的方法;
2. 好并发:当多个应用程序在并发访问数据库时,可以在这些应用程序之间提供一个隔离方法,以防止彼此的操作互相干扰。
事务主要用于处理操作量大,复杂度高的数据。比如说,在人员管理系统中,你删除一个人员,即需要删除人员的基本资料,也要删除和该人员相关的信息,如信箱,文章等等。这样一组数据库操作语句就构成一个事务。
在 MySQL 命令行的默认设置下,事务都是自动提交的,即执行 SQL 语句后就会马上执行 COMMIT 操作。因此要显式地开启一个事务务须使用命令 BEGIN 或 START TRANSACTION,或者执行命令 SET AUTOCOMMIT=0,用来禁止使用当前会话的自动提交。

二、事务的四大特性(ACID)

原子性(Atomicity)

一个事务中的所有操作,要么全部完成,要么全部不完成,不会结束在中间某个环节。事务在执行过程中发生错误,会被回滚到事务开始前的状态,就像这个事务从来没有执行过一样。

一致性(Consistency)

事务应确保数据库的状态从一个一致状态转变为另一个一致状态。一致状态的含义是数据库中的数据应满足完整性约束。

隔离性(Isolation)

多个事务并发执行时,一个事务的执行不应影响其他事务的执行。

持续性(Durability)

事务处理结束后,对数据的修改就是永久的,即便系统故障也不会丢失。

举个栗子

账户A向账户B转账有6个步骤:

  1. 从A账号中把余额读出来(500);
  2. 对A账号做减法操作(500-100);
  3. 把结果写回A账号中(400);
  4. 从B账号中把余额读出来(500);
  5. 对B账号做加法操作(500+100);
  6. 把结果写回B账号中(600)。

原子性

保证1-6所有步骤要么都执行,要么都不执行。一旦在执行某一步骤的过程中发生问题,就需要执行回滚操作。假如执行到第5步的时候,B账户突然不可用(比如被注销),那么之前的所有操作都应该回滚到执行事务之前的状态。

一致性

在转账之前,A和B的账户中共有500+500=1000元钱。在转账之后,A和B的账户中共有400+600=1000元。也就是说,数据的状态在执行该事务操作之后从一个状态改变到了另外一个状态。同时一致性还能保证账户余额不会变成负数等。

隔离性

在A向B转账的整个过程中,只要事务还没有提交,查询A账户和B账户的时候,两个账户里面的钱的数量都不会有变化。
如果在A给B转账的同时,有另外一个事务执行了C给B转账的操作,那么当两个事务都结束的时候,B账户里面的钱应该是A转给B的钱加上C转给B的钱再加上自己原有的钱。

持久性

一旦转账成功(事务提交),两个账户的里面的钱就会发生永久性的变化。

三、并发控制

如果事务不保持隔离性来进行并发控制,就会出现一些异常情形。

1、脏读(Dirty Read)

事务A修改了一个数据,但未提交,事务B读到了事务A未提交的更新结果,如果事务A提交失败,事务B读到的就是脏数据。

2、不可重复读(Not Repeatable Read)

在同一个事务中,对于同一份数据读取到的结果不一致。不可重复读出现的原因就是事务并发修改记录,要避免这种情况,最简单的方法就是对要修改的记录加锁,这回导致锁竞争加剧,影响性能。

3、幻读(Phantom Read)

在同一个事务中,同一个查询多次返回的结果不一致。幻读是由于并发事务增加记录导致的,这个不能像不可重复读通过记录加锁解决,因为对于新增的记录根本无法加锁。
幻读和不可重复读都是读取了另一条已经提交的事务(这点就脏读不同),所不同的是不可重复读查询的都是同一个数据项,而幻读针对的是一批数据整体(比如数据的个数)。

4、第一类丢失更新(Update Lost)

此种更新丢失是因为回滚的原因,所以也叫回滚丢失。两个事务同时读取到一个值,事务A更新成功,事务B更新失败,更新失败的事务B因为回滚把更新成功的事务A所做的修改也回滚了。此时事务A的更新丢失。

5、第二类丢失更新(Second Update Lost)

此种更新丢失是因为更新被其他事务给覆盖了,也可以叫覆盖丢失。两个事务同事读取到一个值,且均更新成功。但是后更新的事务B覆盖了先前更新完成的事务A,导致事务A的更新丢失。

四、隔离级别

有这么多的问题存在,不做好隔离性就会有许许多多的坑。但实际上也并不是所有的问题都是一定要避免的,具体还得看业务需求和数据库的负载要求。
值得注意的是,如果所有事务都是顺序执行的,这些异常情况都不复存在。都是有多个事务互相影响造成的,所以我们要用某种方式将他们分隔开,这种隔离开的实现一般由数据库锁实现。

1、读未提交(Read Uncommitted)

该隔离级别指即使一个事务的更新语句没有提交,但是别的事务可以读到这个改变,几种异常情况都可能出现。极易出错,没有安全性可言,基本不会使用。此级别无法解决任何并发事务问题。

2、读已提交(Read Committed)

该隔离级别指一个事务只能看到其他事务的已经提交的更新,看不到未提交的更新,消除了脏读和第一类丢失更新,这是大多数数据库的默认隔离级别,如Oracle,Sqlserver。

3、可重复读(Repeatable Read)

该隔离级别指一个事务中进行两次或多次同样的对于数据内容的查询,得到的结果是一样的,但不保证对于数据条数的查询是一样的,只要存在读改行数据就禁止写,消除了不可重复读和第二类更新丢失,这是Mysql数据库的默认隔离级别。

4、串行化(Serializable)

事务执行的时候不允许别的事务并发执行,完全串行化的读,只要存在读就禁止写,但可以同时读,消除了幻读。这是事务隔离的最高级别,虽然最安全最省心,但是效率太低,一般不会用。

五、锁分类

一般分为悲观锁和乐观锁,悲观锁一般就是我们通常说的数据库锁机制,乐观锁一般是指用户自己实现的一种锁机制。

1、悲观锁按照性质划分:

对数据被修改持保守态度,认为数据随时会被修改,所以整个数据处理过程都需要将数据加锁。

1.1共享锁(S)

也称读锁,用于不更改或不更新数据的读取操作,如 SELECT 语句。多个事务可以同时读,但不能写,除非其余所有事务释放S锁。

1.2排他锁(X)

也称写锁,用于数据修改操作,例如 INSERT、UPDATE 或 DELETE。 确保不会同时对同一资源进行多重更新,只有加了X锁的事务才能读写对象直到释放。

1.3更新锁(U)

用于可更新的资源中。提前预定对此对象加X锁,它允许其他事务读(即施加S锁),但不再允许施加X锁或U锁。当进行一次更新操作时,有三个步骤:读取数据、计算、写入数据 。在前两步U锁允许其他事务来读,但当到第三步写入前U锁会升级为X锁。这能防止当多个会话在读取、锁定以及随后可能进行的资源更新时发生常见形式的死锁。

1.4意向锁

数据库引擎使用意向锁来保护共享锁或排他锁放置在锁层次结构的底层资源上。
意向锁有一个很重要的功能是提高数据库引擎在较高的粒度级别检测锁冲突的效率。
比如在表级设置意向锁可以防止另一个事务随后在包含那一页的表上获取X锁。意向锁可以提高性能,因为数据库引擎仅在表级检查意向锁来确定事务是否可以安全地获取该表上的锁。 而不需要检查表中的每行或每页上的锁以确定事务是否可以锁定整个表。
当然,意向锁包括意向共享 (IS)、意向排他 (IX) 以及意向排他共享 (SIX)。可以顾名思义来理解。

2、悲观锁按照粒度划分:行锁、页锁、表锁

3、乐观锁

乐观锁认为每次操作数据不会有其他事务来同步操作,所以不加锁,但在更新的时候会以某种方式判断此期间是否有数据被修改,这需要用户自己去实现。
在有数据库自己提供悲观锁的情况下,乐观锁的意义是解决读操作在实际应用中比写操作多很多很多,而一个更新锁或者排他锁会阻塞所有读取,降低吞吐量,然后锁还得释放,这些都需要开销。所以我们只要解决极少量的更新操作的同步问题。如果你没有数据库响应效率、吞吐量瓶颈问题,可以不用使用乐观锁,这会增加复杂度和风险。


乐观锁的实现可以通过版本号、时间戳、待更新字段、所有字段。
以版本号举例,给数据增加一个版本标识,在数据库上就是表中增加一个version字段,每次更新把这个字段加1,读取数据的时候把version读出来,更新的时候比较,如果与开始读取的version一致则更新,否则抛出无法更新的通知由用户决定后续怎么处理。

六、MySQL事务控制语句

用过Python3连接MySQL服务器的一个库PyMySQL的人,对事务控制语句一定有印象。第一种方式看着就会感觉亲切。

1、用 BEGIN, ROLLBACK, COMMIT来实现:

  • BEGIN 开始一个事务
  • ROLLBACK 事务回滚
  • COMMIT 事务确认

2、直接用 SET 来改变 MySQL 的自动提交模式:

  • SET AUTOCOMMIT=0 禁止自动提交
  • SET AUTOCOMMIT=1 开启自动提交

猜你喜欢

转载自blog.csdn.net/zhchs2012/article/details/79754997