




问题的引入
我的理解是,在数据库方面,就同时有两个事务,第一个,是A操作带来的,他锁定自己的行信息,修改余额,然后准备去锁定B的行信息;第二个,是B带来的,B先锁定自己的行信息,修改余额,然后准备去锁定A的行信息。
以上是能想到的解决你提出的这个场景的几种方法,关于避免死锁的方法太多了,还有其他建立索引, 设置事务隔离级别,编写应用程序让进程持有锁的时间尽可能短,等等。
下面来系统学习学习mysql事务及锁机制

1. 事务的引入
2. 事务的基本概念

3. 事务的四大特性
数据库事务 transanction 正确执行的四个基本要素。ACID,原子性(Atomicity)、一致性(Correspondence)、隔离性(Isolation)、持久性(Durability)。
事务的并发执行
事务故障或系统故障
并发控制技术保证了事务的隔离性,使数据库的一致性状态不会因为并发执行的操作被破坏。
日志恢复技术保证了事务的原子性,使一致性状态不会因事务或系统故障被破坏。同时使已提交的对数据库的修改不会因系统崩溃而丢失,保证了事务的持久性。

4. 事务的实现原理
事务的原子性是通过undo log来实现的
事务的持久性是通过redo log来实现的
事务的隔离性是通过(读写锁+MVCC)来实现的
事务的一致性是通过原子性,持久性,隔离性来实现的!!!
4.1 原子性实现原理:Undo Log
当delete一条记录时,undo log中 会记录一条对应的Insert记录
当insert一条记录时,undo log中会记录一条 对应的delete记录
当update一条记录时,它记录一条 对应相反的update记录
4.2. 持久性实现原理:Redo Log

5. Mysql的隔离级别(解决办法)
读未提交(READ UNCOMMITTED):对事务处理的读取没有任何限制,不推荐
读已提交(READ COMMITTED) ;
可重复读(REPEATABLE READ)
串行化(SERIALIZABLE)
| 事务的隔离级别 | 脏读 | 不可重复读 | 幻读 |
| 读未提交(READ UNCOMMITTED) | ![]() | ![]() | ![]() |
| 读已提交(READ COMMITTED) | ![]() | ![]() | |
| 可重复读(REPEATABLE READ) | ![]() | ||
| 串行化(SERIALIZABLE) |
6. 隔离性的实现原理:锁
共享锁: 共享锁定是将对象数据变为只读形式,不能进行更新,所以也成为读取锁定;
排他锁: 排他锁定是当执行INSERT/UPDATE/DELEE的时候,其它事务不能读取该数据,因此也成为写入锁定。
记录
表
数据库
可能出现的问题:
基于时间戳的并发控制
基于有效性检查的并发控制
基于快照隔离的并发控制
6.1 锁的分类
共享锁Shared Locks (简称S锁, 属于行锁)
排他锁Exclusive Locks (简称X锁,属于行锁)
意向共享锁Intention Shared Locks (简称IS锁, 属于表锁)
意向排他锁Intention Exclusive Locks (简称 IX锁,属于表锁)
自增锁AUTO-INC Locks
6.1.1 共享锁
select * from student where id= 1 lock in share mode;
select * from student where id = 1;(读取数据没问题)
update student set name='hehe' whereid =1;
6.1.2 排它锁
select * from student where id= 1 for update;
select * from student where id= 1 for update;
select * from student where id= 1 lock in share mode;
6.1.3 向共享锁和意向排他锁
6.1.4 自增锁
SHOW VARIABLES LIKE ' innodb_ _autoinc_ .lock_ mode';
-.-
默认值1代表连续,事务未提交则id永久丢失
7. 故障及故障恢复
系统会为每个事务开辟一个私有工作区
事务读操作将从磁盘中拷贝数据项到工作区中,在执行写操作前所有的更新都作用于工作区中的拷贝
事务的写操作将把数据输出到内存的缓冲区中,等到合适的时间再由缓冲区管理器将数据写入到磁盘
故障
在事务提交前出现故障,但是事务对数据库的部分修改经写入磁盘数据库中。这导致了事务的原子性被破坏。
在系统崩溃前事务已经提交,但数据还在内存缓冲区中,没有写入磁盘。系统恢复时将丢失此次已提交的修改。这是对事务持久性的破坏。
故障恢复
撤销事务undo:将事务更新的所有数据项恢复为日志中的旧值
重做事务redo:将事务更新的所有数据项恢复为日志中的新值。
事务正常回滚/因事务故障中止将进行redo
系统从崩溃中恢复时将先进行redo再进行undo。






