—— 数据库事务是指作为单个逻辑工作单元执行的一系列操作,这些操作要么全做,要么全部做,是一个不可分割的工作单元。
—— 事务的开始与结束可以由用户显示的控制。如果用户没有显式地定义事务,则由DBMS按照默认的规定自动划分事务。事务分为 原子性、一致性、独立性 及 持久性 等特点。

  • 事务的原子性是指一个事务要么全部执行,要么不执行。也就是说,一个事物不可能只执行了一半就停止了。比如你从银行取钱,这个事务可以分为两个步骤:①存折减款,②拿到现金。不可能存折钱少了,而钱没取出来。这两步必须同时完成,要么都不完成。

  • 事务的一致性是指事务的运行并不改变数据库中数据的一致性。例如,完整性约束了a+b=10,一个事务改变了a, 那么b 也应该随之改变。举个粒子,张三给李四转账100元。事务要做的是从张三账户上减掉100元,李四账户上加上100元。一致性的含义是其他事务要么看到张三还没有给李四转账的状态,要么张三已经成功转账给李四的状态,而对于张三少了100元,李四还没加上100元这个中间状态是不可见的。

  • 事务的独立性是指两个以上的事务不会出现交错执行的状态,因为这样可能会导致数据不一致。

  • 事务的持久性是指事务运行成功后,系统的更新是永久的,不会无缘无故地回滚。

操作数据库为什么需要进行事务控制?

比如说:做了一个图书管理系统,有人要借书,那么步骤是这样的:

  1. 系统读书,读者的条形码
  2. 系统把书的状态变为借出,
  3. 图书-读者表中 增加该书和借书者的id
  4. 读者的借书数量+1

问题就出现了,数据库执行完1,2俩个步骤,3步骤出现错误,比如说系统奔溃了,这时候会出现bug.
书被借出,但没人借走。要用事务捆绑这几个动作,如果1,2,3,4有错误发生,则回滚数据库。
Try{ 1;2;3;4;}catch(exception e){ roll back;}
感觉说的不错,浅显易懂~
来自百度问答:https://zhidao.baidu.com/question/588844614.html

脏读、幻读与不可重复读

https://juejin.im/entry/6844903665367547918

MySQL 数据隔离级别

首先 MySQL 里有四个隔离级别:Read uncommttied(可以读取未提交数据)、Read committed(可以读取已提交数据)、Repeatable read(可重复读)、Serializable(可串行化)。
在 InnoDB 中,默认为 Repeatable 级别,InnoDB 中使用一种被称为 next-key locking 的策略来避免幻读(phantom)现象的产生。
使用 select @@tx_isolation; 可以查看 MySQL 默认的事务隔离级别。
不同的事务隔离级别会导致不同的问题:
数据库事务(transaction) - 图1

脏读、幻读、不可重复读的概念

脏读

所谓脏读是指一个事务中访问到了另外一个事务未提交的数据,如下图:
数据库事务(transaction) - 图2
如果会话 2 更新 age 为 10,但是在 commit 之前,会话 1 希望得到 age,那么会获得的值就是更新前的值。或者如果会话 2 更新了值但是执行了 rollback,而会话 1 拿到的仍是 10。这就是脏读。

幻读

一个事务读取2次,得到的记录条数不一致:
数据库事务(transaction) - 图3
上图很明显的表示了这个情况,由于在会话 1 之间插入了一个新的值,所以得到的两次数据就不一样了。

不可重复读

一个事务读取同一条记录2次,得到的结果不一致:
数据库事务(transaction) - 图4
由于在读取中间变更了数据,所以会话 1 事务查询期间的得到的结果就不一样了。

解决方案

解决方案也就是上文提到的四种隔离级别,他们可以最大程度避免以上三种情况的发生:

未授权读取

也称为读未提交(Read Uncommitted):允许脏读取,但不允许更新丢失。如果一个事务已经开始写数据,则另外一个事务则不允许同时进行写操作,但允许其他事务读此行数据。该隔离级别可以通过“排他写锁”实现。

授权读取

也称为读提交(Read Committed):允许不可重复读取,但不允许脏读取。这可以通过“瞬间共享读锁”和“排他写锁”实现。读取数据的事务允许其他事务继续访问该行数据,但是未提交的写事务将会禁止其他事务访问该行。

可重复读取(Repeatable Read)

可重复读取(Repeatable Read):禁止不可重复读取和脏读取,但是有时可能出现幻读数据。这可以通过“共享读锁”和“排他写锁”实现。读取数据的事务将会禁止写事务(但允许读事务),写事务则禁止任何其他事务。

序列化(Serializable)

序列化(Serializable):提供严格的事务隔离。它要求事务序列化执行,事务只能一个接着一个地执行,不能并发执行。仅仅通过“行级锁”是无法实现事务序列化的,必须通过其他机制保证新插入的数据不会被刚执行查询操作的事务访问到。
隔离级别越高,越能保证数据的完整性和一致性,但是对并发性能的影响也越大。对于多数应用程序,可以优先考虑把数据库系统的隔离级别设为Read Committed。它能够避免脏读取,而且具有较好的并发性能。尽管它会导致不可重复读、幻读和第二类丢失更新这些并发问题,在可能出现这类问题的个别场合,可以由应用程序采用悲观锁或乐观锁来控制。

Mysql死锁

image.png
排它锁(X锁)和共享锁(S锁):

  • 所谓X锁,是事务T对数据A加上X锁时,只允许事务T读取和修改数据A
  • 所谓S锁,是事务T对数据A加上S锁时,其他事务只能再对数据A加S锁,而不能加X锁,直到T释放A上的S锁若事务T对数据对象A加了S锁,则T就可以对A进行读取,但不能进行更新(S锁因此又称为读锁),在T释放A上的S锁以前,其他事务可以再对A加S锁,但不能加X锁,从而可以读取A,但不能更新A.


参考:
https://www.jianshu.com/p/342f526dbbc2 mysql X锁和S锁
https://blog.csdn.net/Saintyyu/article/details/104330881 IGNORE,REPLACE,ON DUPLICATE KEY UPDATE在避免重复插入记录时存在的问题及最佳实践