数据库开发 - 事务 死锁分析与解决
为什么80%的码农都做不了架构师?>>>
#死锁分析与解决 ##事务并发执行
##事务持锁 MySQL数据库是以行加锁的方式,避免不同事务,对同一行数据库进行同时修改的。首先来看事务一,对张三这条记录的Account字段进行修改,需要持有张三这条数据库的行锁。然后事务二也同时并发执行,事务二首先修改李四这条数据库记录的Corp字段,持有李四这条数据库的行锁。
此时两个事务各持有一个行锁,但是接下来事务一要持有事务二的行锁,事务二要持有事务一的行锁。这样就形成了事务一与事务二相互等待,导致两个事务都无法继续执行下去。
##死锁 死锁:指两个或者两个以上的事务,在执行过程中,因争夺锁资源而造成的一种互相等待的现象。
死锁必须是两个或者两个以上的事务,单个事务不可能发生死锁。死锁是因为争夺锁资源,导致相互持有锁资源,导致相互等待。需要外部干涉的现象。
##死锁产生的必要条件
- 互斥
- 并发执行的事务为了进行必要的隔离保证执行正确,在事务结束前,需要对修改的数据库记录持锁,保证多个事务对相同数据库记录串行修改
- 对于大型并发系统无法避免
- 请求与保持
- 一个事务申请多个资源,已经持有一个资源锁,等待另外一个资源锁
- 死锁仅发生在请求两个或者两个以上的锁对象
- 由于应用实际需要,难以消除
- 不剥夺
- 已经获得锁资源的事务,在未执行前,不能被强制剥夺,只能使用完时,由事务自己释放。
- 一般用于已经出现死锁时,通过破坏该条件达到解除死锁的目的。
我们只要强制回滚某个持有锁的事务,让该事务执行完毕。这样就解除了死锁。
- 一般用于已经出现死锁时,通过破坏该条件达到解除死锁的目的。
- 数据库系统通常通过一定的死锁检测机制发现死锁,强制回滚代价相对较小的事务,达到解除死锁的目的。
- 环路等待
- 发生死锁时,必然存在一个事务--所的环形链。
- 按照同一顺序获取锁,可以破坏该条件。
- 通过分析死锁事务之间的锁竞争关系,调整SQL的顺序,达到消除死锁的目的。
##MySQL中的锁 排它锁我们用X来表示,共享锁我们用S来表示。所谓排它锁,就是和任何的锁相互冲突,如果一个事务添加了排它锁,不管其他事务添加任何的锁,都必须要等待这个事务。所谓共享锁是指,多个事务可以共享一把锁,多个锁可以兼容,也就是说,事务一获取共享锁的情况下,事务二还是要加共享锁,则可以直接获取无需等待。如果事务二需要添加一个排它锁,则必须要等待。
##加锁方式
- 外部加锁:
- 由应用程序添加,锁依赖关系较容易分析
这种依赖关系可以通过分析SQL语句得到,一旦出现死锁时,相对来说比较容易分析
- 由应用程序添加,锁依赖关系较容易分析
- 共享锁(S) :
SELECT * FROM table LOCK IN SHARE MODE
- 共享锁(S) :
- 排它锁(X):
SELECT * FROM table FOR UPDATE
- 排它锁(X):
- 内部加锁:
- 为了实现ACID特性,由数据库系统内部自动添加
- 加锁规则繁琐,与SQL执行计划、事务隔离级别、表索引结构有关
- 共享锁(S)和排它锁(X) 要求:对外部加锁能够掌握,对内部加锁的一些基本的场景有了解。对于复杂场景的内部加锁可以查阅专业的MySQL内核的数据进行参考。
##哪些SQL需要持有锁 在MySQL数据库中,所有的SELECT读
- 快照读:
Innodb
实现了多版本控制(MVCC),支持不加锁快照读。
- 所有SELECT操作是不加锁的,
SELECT * FROM table WHERE...
- 所有SELECT操作是不加锁的,
- 这样可以保证SELECT性能,能够保证同一个SELECT结果集是一致的
- 不能保证同一个事务内部,SELECT语句和其他语句的数据一致性,如果业务需要,需通过外部显示加锁。
需要持锁的SQL语句
- 当前读:
SELECT * FROM table LOCK IN SHARE MODE
SELECT * FROM table FOR UPDATE
UPDATE FROM table SET ...
INSERT INTO...
DELETE FROM table...
增删改的加锁与内部的隔离级别息息相关,我们是不允许出现幻读的现象,有可能会加一些间隙锁,避免出现幻读的现象。
##SQL加锁分析 UPDATE user SET account=0 WHERE id = 1
语句,直接在行记录进行加排他锁,由于快照读的原因此时SELECT操作是不会被阻塞的,如果是SELECT FOR UPDATE或者是SELECT IN SHARE MODE,都是会被阻塞的。
SELECT userName FROM user WHERE id=1 IN SHARE MODE
对行记录添加的是共享锁,此时,如果其他事务要执行SELECT IN SHARE MODE的话,对同一行记录还是可以进行执行的。如果外部其他事务要执行SELECT FOR UPDATE的话,则一定会被阻塞。
##分析死锁的常用办法 MySQL数据库会自动分析死锁,并强制回滚代价最小的事务,不需要开发人员去关心。死锁的解除MySQL会自动帮助我们去做。但是我们需要在死锁解除以后,分析死锁产生的SQL语句,避免死锁再次产生。如下方法捕获死锁的SQL语句。
MySQL命令:
show engine innodb status
执行完毕以后,会有一大段内容出现其中,标红部分是关于死锁的,列出了发生死锁时两个等待的SQL语句,然后列出了系统强制回滚的是哪个事务,知道了这些SQL语句,可以分析SQL语句的加锁方式,来调整SQL语句的顺序,改变SQL语句保证按顺序获取锁资源,这样就可以有效的避免死锁的产生。
#附件 ##自己在MySQL数据库当中,执行
show engine innodb status
得到的结果
| InnoDB | |
=====================================
2016-10-08 22:04:17 0x7f61915e0700 INNODB MONITOR OUTPUT
=====================================
Per second averages calculated from the last 45 seconds
-----------------
BACKGROUND THREAD
-----------------
srv_master_thread loops: 41 srv_active, 0 srv_shutdown, 12620 srv_idle
srv_master_thread log flush and writes: 12661
----------
SEMAPHORES
----------
OS WAIT ARRAY INFO: reservation count 73
OS WAIT ARRAY INFO: signal count 57
RW-shared spins 0, rounds 93, OS waits 45
RW-excl spins 0, rounds 0, OS waits 0
RW-sx spins 0, rounds 0, OS waits 0
Spin rounds per wait: 93.00 RW-shared, 0.00 RW-excl, 0.00 RW-sx
------------
TRANSACTIONS
------------
Trx id counter 12583
Purge done for trx's n:o < 12583 undo n:o < 0 state: running but idle
History list length 174
LIST OF TRANSACTIONS FOR EACH SESSION:
---TRANSACTION 421532535461264, not started
0 lock struct(s), heap size 1136, 0 row lock(s)
---TRANSACTION 421532535460352, not started
0 lock struct(s), heap size 1136, 0 row lock(s)
---TRANSACTION 421532535459440, not started
0 lock struct(s), heap size 1136, 0 row lock(s)
---TRANSACTION 421532535458528, not started
0 lock struct(s), heap size 1136, 0 row lock(s)
---TRANSACTION 421532535457616, not started
0 lock struct(s), heap size 1136, 0 row lock(s)
--------
FILE I/O
--------
I/O thread 0 state: waiting for completed aio requests (insert buffer thread)
I/O thread 1 state: waiting for completed aio requests (log thread)
I/O thread 2 state: waiting for completed aio requests (read thread)
I/O thread 3 state: waiting for completed aio requests (read thread)
I/O thread 4 state: waiting for completed aio requests (read thread)
I/O thread 5 state: waiting for completed aio requests (read thread)
I/O thread 6 state: waiting for completed aio requests (write thread)
I/O thread 7 state: waiting for completed aio requests (write thread)
I/O thread 8 state: waiting for completed aio requests (write thread)
I/O thread 9 state: waiting for completed aio requests (write thread)
Pending normal aio reads: [0, 0, 0, 0] , aio writes: [0, 0, 0, 0] ,ibuf aio reads:, log i/o's:, sync i/o's:
Pending flushes (fsync) log: 0; buffer pool: 0
373 OS file reads, 290 OS file writes, 181 OS fsyncs
0.00 reads/s, 0 avg bytes/read, 0.00 writes/s, 0.00 fsyncs/s
-------------------------------------
INSERT BUFFER AND ADAPTIVE HASH INDEX
-------------------------------------
Ibuf: size 1, free list len 0, seg size 2, 0 merges
merged operations:insert 0, delete mark 0, delete 0
discarded operations:insert 0, delete mark 0, delete 0
Hash table size 34673, node heap has 0 buffer(s)
Hash table size 34673, node heap has 0 buffer(s)
Hash table size 34673, node heap has 0 buffer(s)
Hash table size 34673, node heap has 0 buffer(s)
Hash table size 34673, node heap has 0 buffer(s)
Hash table size 34673, node heap has 0 buffer(s)
Hash table size 34673, node heap has 0 buffer(s)
Hash table size 34673, node heap has 0 buffer(s)
0.00 hash searches/s, 0.00 non-hash searches/s
---
LOG
---
Log sequence number 3162168
Log flushed up to 3162168
Pages flushed up to 3162168
Last checkpoint at 3162159
0 pending log flushes, 0 pending chkp writes
118 log i/o's done, 0.00 log i/o's/second
----------------------
BUFFER POOL AND MEMORY
----------------------
Total large memory allocated 137428992
Dictionary memory allocated 317905
Buffer pool size 8191
Free buffers 7813
Database pages 378
Old database pages 0
Modified db pages 0
Pending reads 0
Pending writes: LRU 0, flush list 0, single page 0
Pages made young 0, not young 0
0.00 youngs/s, 0.00 non-youngs/s
Pages read 343, created 35, written 143
0.00 reads/s, 0.00 creates/s, 0.00 writes/s
No buffer pool page gets since the last printout
Pages read ahead 0.00/s, evicted without access 0.00/s, Random read ahead 0.00/s
LRU len: 378, unzip_LRU len: 0
I/O sum[0]:cur[0], unzip sum[0]:cur[0]
--------------
ROW OPERATIONS
--------------
0 queries inside InnoDB, 0 queries in queue
0 read views open inside InnoDB
Process ID=2247, Main thread ID=140057180620544, state: sleeping
Number of rows inserted 175, updated 14, deleted 3, read 356
0.00 inserts/s, 0.00 updates/s, 0.00 deletes/s, 0.00 reads/s
----------------------------
END OF INNODB MONITOR OUTPUT
============================
转载于:https://my.oschina.net/hava/blog/755451
数据库开发 - 事务 死锁分析与解决相关推荐
- 并发访问oracle数据库的数据死锁分析和解决措施,解决Oracle数据库死锁
[IT168 技术文档] 介绍 本文我们尝试总结在多个用户并发情况下,如何识别和解决删除操作期间发生的死锁问题,在开始之前,我们先简单描述一下什么是死锁以及什么东西会导致死锁. 死锁 在任何数据库中发 ...
- 数据库死锁分析与解决
一.死锁的表现 1.错误信息是:事务(进程 ID)与另一个进程被死锁在 锁 资源上,并且已被选作死锁牺牲品.请重新运行该事务. 2.错误信息是:事务(进程 ID )与另一个进程被死锁在 锁 | 通信缓 ...
- 转:关于ASP操作Access数据库时出现死锁.ldb的解决方法
Asp操作Access数据库时出现死锁.ldb导致网站访问缓慢的问题描述 最近asp网站出现数据库错误,在ftp登陆后发现原来的后缀MDB文件多了一个后缀LDB文件,是自动被锁,在一天某个时间段内打不 ...
- 引起SQL数据库超时的问题分析及解决办法
1.由于数据库设计问题造成SQL数据库新增数据时超时 症状: Microsoft OLE DB Provider for SQL Server 错误 '80040e31' ([ODBC SQL S ...
- Asp 操作Access数据库时出现死锁.ldb的解决方法
问题: 最近经常用的asp网站"搬家"到一个昂贵的服务器时候,出现这个问题,访问后台时候,出现数据库错误的字样,在ftp登陆后发现原来的后缀MDB文件多了一个后缀LDB文件,百度搜 ...
- MySQL事务原理分析(ACID特性、隔离级别、锁、MVCC、并发读异常、并发死锁以及如何避免死锁)
MySQL事务原理分析(ACID特性.隔离级别.锁.MVCC.并发读异常.并发死锁以及如何避免死锁) 一.事务 目的 组成 特征 事务空间语句 二.ACID特性 原子性(A) 隔离性(I) 持久性(d ...
- Linux服务器开发【有用知识】—MySQL事务原理分析
前言 今天的目标是学习MySQL事务原理分析,但是却似乎总是非常不顺利,概念和实操实在多到令人发指,故干脆轻松学完一节课,等到时机到了再重新刷一遍吧! 一.事务是什么? 将数据库从一致性状态转化成另一 ...
- mysql 1061原因_MySQL死锁问题分析及解决方法实例详解(转)
出处:http://www.jb51.net/article/51508.htm MySQL死锁问题是很多程序员在项目开发中常遇到的问题,现就MySQL死锁及解决方法详解如下: 1.MySQL常用存储 ...
- 数据库关于事务的详解分析(全)包含面试常问的细节
目录 前言 1. 定义 2. 四个特性(ACID) 3. 面临的问题 4. 四个隔离级别 5. 四个基本术语 6. 实战 前言 在敲代码的时候,提交事务.事务回滚等,事务二字确官方笼统,不知道具体什么 ...
最新文章
- 排列和组合简单的递归思路以及C++实现
- (译) 函数式 JS #2: 函数!
- python for-Python for windows官方版
- WIFI搜索的到别人,却找不到自己家的wifi
- Flask之threading.loacl方法
- centos 安装软件
- 9本Java程序员必读的书
- springmvc 传对象报400_springmvc 通过对象来接收参数,为什么默认会返回该对象?
- win10+Idea遇到一个bug的解决办法
- 根据出库、入库表,实现对库存的信息查询
- 陈继儒 -- 《小窗幽记》
- ASP.NET 班级网站-程序+配置文档
- 计算机WIN7动态硬盘分区,如何创建Win7虚拟磁盘分区
- 零电压开关(ZVS)电路原理与设计(整理)
- 主引导记录(MBR)的反汇编分析
- 面试官问我new Vue阶段做了什么?
- 北大国际医院:基于互联网医疗的移动诊疗方案分析与设计
- SpringBoot导入导出你会用吗?(EasyPoi)
- 2022-2027年中国婚纱礼服行业市场全景评估及发展战略规划报告
- [Python]tabulate可如此优雅地创建表格
热门文章
- air写文件 SecurityError: fileWriteResource 时报错的解决方法
- SQL 去除重复、获取最新记录
- 函数矩阵OpenGL中glFrustum()和gluPerspective()的相互转换
- k8s核心技术-Pod(调度策略)_影响Pod调度(节点亲和性)---K8S_Google工作笔记0026
- STM32工作笔记0040---认识MOS管
- Web前端工作笔记002---json数据查询的方法_json查询大全,JsonSQL数据查询,jfunk数据查询
- Linux学习笔记004----CentOS7 提升普通用户权限到Root权限
- Ui学习笔记---EasyUI的使用方法,EasyLoader组件使用
- C语言逐行读取文件内容
- SVM支持向量机,我用到的自学材料