最近使用flask-sqlalchemy时,进行测试的时候发现日志中打印出了MySql死锁错误,查看Mysql日志发现是因为有俩条sql出现了死锁:

Deadlock found when trying to get lock; try restarting transaction

查看方法是执行:show engine innodb status\G

具体原因分析:

1. 涉及的俩个sql:

update ks_saei_instances set status = :status where last_worktime < :now - :timeout ;
update ks_saei_instances set request_num = request_num+1 where instance_id = :instanceid ;

2. 这俩个sql死锁的很奇怪,因为第二sql只会锁住一条记录,且只加一次锁(记录X锁) , 所以,应该只是会锁等待而不会死锁

后面换了一种实现,当然就不会有死锁了。

3.其实本人对上下文的所有sql都做了分析,里面没有相关的sql了(就是说没有操作这个表的sql),所以这个问题先这样了。。。。

附mysql加锁分析

首先,mysql不是对记录加锁,而是对索引加锁

其次,针对不同索引和隔离级别加不同的锁,参考这里:http://hedengcheng.com/?p=771

1. 如果字段为主键索引,隔离级别为RC(Read Committed)

  只会在主键所在的记录的索引项加一个X锁

2. 如果字段为唯一索引,隔离级别为RC

  X锁住字段对应的唯一索引项,然后X锁住该记录对应的主键索引项(聚簇索引,如果没有主键,会自动生成隐含的聚簇索引)

3. 如果字段为非唯一索引,隔离级别为RC

  X锁住字段值对应的所有索引项,然后X锁住这些记录上对应的主键索引项

4. 如果字段没有索引,隔离级别为RC

  所有的记录都被加上一个X锁

5. 如果字段为主键,隔离级别为RR(Repeatable Read)

  只会在主键所在的记录的索引项加一个X锁

6. 如果字段为唯一索引,隔离级别为RR

  X锁住字段对应的唯一索引项,然后X锁住该记录对应的主键索引项(聚簇索引,如果没有主键,会自动生成隐含的聚簇索引)

7. 如果字段为非唯一索引,隔离级别为RR

  对每一个符合字段值的索引添加索引项的X锁,然后在GAP上加GAP锁,最后在聚簇索引项加一个X锁,下一个也是如此做

8. 如果字段没有索引,隔离级别为RR

  所有的记录都被加上一个X锁,所有的GAP(记录数+1)都会加一个GAP锁。这对并发有很大影响(杜绝所有的并发 更新/删除/插入 操作)

我们根据什么来判断哪些字段会加锁?以下出现“?”的地方的字段都需要加锁

快照读:简单的select操作,属于快照读,不加锁。(当然,也有例外,下面会分析)
  select * from table where ?;

当前读:特殊的读操作,插入/更新/删除操作,属于当前读,需要加锁。
  select * from table where ? lock in share mode;
  select * from table where ? for update;
  insert into table values (…);
  update table set ? where ?;  -- 这里set后面的?不会加锁,如果理解错误请指正
  delete from table where ?;
所有以上的语句,都属于当前读,读取记录的最新版本。并且,读取之后,还需要保证其他并发事务不能修改当前记录,对读取记录加锁。其中,除了第一条语句,对读取记录加S锁 (共享锁)外,其他的操作,都加的是X锁 (排它锁)。

注意:

一个Update操作的具体流程。当Update SQL被发给MySQL后,MySQL Server会根据where条件,读取第一条满足条件的记录,然后InnoDB引擎会将第一条记录返回,并加锁 (current read)。待MySQL Server收到这条加锁的记录之后,会再发起一个Update请求,更新这条记录。一条记录操作完成,再读取下一条记录,直至没有满足条件的记录为止。因此,Update操作内部,就包含了一个当前读。同理,Delete操作也一样。Insert操作会稍微有些不同,简单来说,就是Insert操作可能会触发Unique Key的冲突检查,也会进行一个当前读。

注:针对一条当前读的SQL语句,InnoDB与MySQL Server的交互,是一条一条进行的,因此,加锁也是一条一条进行的。先对一条满足条件的记录加锁,返回给MySQL Server,做一些DML操作;然后在读取下一条加锁,直至读取完毕。

索引创建基本原则:

1. 频繁作为查询条件的字段适合创建索引

2. 唯一性太差的字段不适合建立索引(例如状态字段,它的值可能只有几个,因此不适合做索引)

3. 不要为频繁更新的字段创建索引,因为当你这样做了之后,后续的更新都会重建这个字段的索引

4. 不会出现在where条件中的字段不该建立索引

5. 如果经常同时搜索两列或多列或按两列或多列排序时,索引也很有帮助。例如,如果经常在同一查询中为姓和名两列设置判据,那么在这两列上创建多列索引将很有意义

注意自己的SQL是否使用了索引:MySQL何时使用索引、何时不使用索引。《待续》

【错误记录】flask mysql 死锁的更多相关文章

  1. Mysql插入text类型字段错误记录 com.mysql.jdbc.MysqlDataTruncation: Data truncation: #22001

    一次插入操作报如下错误 com.mysql.jdbc.MysqlDataTruncation: Data truncation: #22001 是说字段值长度超过限制. MySQL TEXT数据类型的 ...

  2. mysql-不恰当的update语句使用主键和索引导致mysql死锁

    背景知识:MySQL有三种锁的级别:页级.表级.行级. MyISAM和MEMORY存储引擎采用的是表级锁(table-level locking):BDB存储引擎采用的是页面锁(page-level ...

  3. JDBC 连接 MySQL 8.0.15+ 常见错误记录

    课后复习 1. No suitable driver found for mysql:jdbc://localhost:3306/test 错误原因: mysql:jdbc://localhost:3 ...

  4. Mysql 死锁的详细分析方法

    用数据库的时候,偶尔会出现死锁,针对我们的业务系统,出现死锁的直接结果就是系统卡顿.客户找事儿,所以我们也在想尽全力的消除掉数据库的死锁.出现死锁的时候,如果只是想解锁,用show full proc ...

  5. 一次MySQL死锁问题解决

    一次MySQL死锁问题解决 一.环境 CentOS, MySQL 5.6.21-70, JPA 问题场景:系统有定时批量更新数据状态操作,每次更新上千条记录,表中总记录数约为500W左右. 二.错误日 ...

  6. 基于innodb_print_all_deadlocks从errorlog中解析MySQL死锁日志

    本文是说明如何获取死锁日志记录的,不是说明如何解决死锁问题的. MySQL的死锁可以通过show engine innodb status;来查看,但是show engine innodb statu ...

  7. MySql 死锁时的一种解决办法【转】

    转自:http://blog.csdn.net/mchdba/article/details/38313881 之前也遇到一次,今天又遇到了这个问题,所以这次必须解决,网上找到这篇文章帮了大忙,方便以 ...

  8. MySQL 死锁与日志二三事

    最近线上 MySQL 接连发生了几起数据异常,都是在凌晨爆发,由于业务场景属于典型的数据仓库型应用,白天压力较小无法复现.甚至有些异常还比较诡异,最后 root cause 分析颇费周折.那实际业务当 ...

  9. MySQL死锁系列-线上死锁问题排查思路

    前言 MySQL 死锁异常是我们经常会遇到的线上异常类别,一旦线上业务日间复杂,各种业务操作之间往往会产生锁冲突,有些会导致死锁异常.这种死锁异常一般要在特定时间特定数据和特定业务操作才会复现,并且分 ...

随机推荐

  1. hdu 4090

    GemAnd Prince Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)To ...

  2. Linux : task work 机制

    task work机制可以在内核中向指定的进程添加一些任务函数,这些任务函数会在进程返回用户态时执行,使用的是该进程的上下文.包括下面的这些API: task_work_add task_work_c ...

  3. 探讨ES6的import export default 和CommonJS的require module.exports

    今天来扒一扒在node和ES6中的module,主要是为了区分node和ES6中的不同意义,避免概念上的混淆,同时也分享一下,自己在这个坑里获得的心得. 在ES6之前 模块的概念是在ES6发布之前就出 ...

  4. vue父与子通信

    个人理解并整理如下 一.父传子 prop传参 父组件传递参数<x-scoll :class="red"></x-scoll> 子组件props:[" ...

  5. ES6新语法之let关键字;有别于传统关键字var的使用

    ES6新语法于2015年发布:而我这个前端小白在17年才接触到.惭愧惭愧!!不过到目前为止,似乎只有FireFox和Chrome对ES6的支持相对良好.不过既然人家ES6已经出来了,还是要跟上技术的潮 ...

  6. 用CSS的方法如何让一个元素不可见?(面试题目)

    面试中看到这个问题,自己想的不全面,下面整理下,一起学习: 一.CSS元素隐藏 在CSS中,让元素隐藏(指屏幕范围内肉眼不可见)的方法很多,有的占据空间,有的不占据空间:有的可以响应点击,有的不能响应 ...

  7. Spring Boot—14JdbcTemplate

    pom.xml <dependency> <groupId>org.springframework.boot</groupId> <artifactId> ...

  8. 那些年vue踩过的坑

    1.前言 学习Vue前端框架已经一个月了,作为一个web刚入门的菜鸟,在学习的过程中,网上有些技术博客往往没有什么可以借鉴的地方,在这里 我特意将我从开始一直到登录的过程记录下来.希望看到我的文章的朋 ...

  9. 云卡门禁苹果SDK_BLEDOOR_SDK_IOS_2016_12_15

    // // BLElib.h // BLElib // // Created by szbosk on 16/8/16. // Copyright © 2016年 szbosk. All rights ...

  10. mysql 存储引擎 配置文件my.ini 的配置方式

    如果想使修改后的参数生效,须重新启动MySQL服务器. #存储引擎设置 default-storage-engine = INNODB