• 分享insert into select遇到的死锁问题(项目实战)


    【辰兮要努力】:hello你好我是辰兮,很高兴你能来阅读,昵称是希望自己能不断精进,向着优秀程序员前行!

    博客来源于项目以及编程中遇到的问题总结,偶尔会有读书分享,我会陆续更新Java前端、后台、数据库、项目案例等相关知识点总结,感谢你的阅读和关注,希望我的博客能帮助到更多的人,分享获取新知,大家一起进步!

    吾等采石之人,应怀大教堂之心,愿我们奔赴在各自的热爱里…


    一、死锁问题

    最近在涉及到大数据量数据表数据的迁移时候,使用到了insert into select,遇到了部分死锁问题,遇到了一些坑,现整理分享!

    在这里插入图片描述

    我出现死锁的原因可能是因为业务逻辑过于复杂,最上层加了事务,导致业务流程执行太慢,事务未提交,其余线程可能使用到了相同的数据表,前一个资源未释放导致死锁。

    最后排查业务代码和两个东西有关,一个是事务的使用,一个是insert into select的应用

    ### Cause: com.mysql.jdbc.exceptions.jdbc4.MySQLTransactionRollbackException: Lock wait timeout exceeded; try restarting transaction
    ; SQL []; Lock wait timeout exceeded; try restarting transaction; nested exception is com.mysql.jdbc.exceptions.jdbc4.MySQLTransactionRollbackException: Lock wait timeout exceeded; try restarting transaction
    
    • 1
    • 2

    在这里插入图片描述

    死锁对应的效果

    在这里插入图片描述
    用命令行的方式杀死MySQL线程

    -- 查询当前运行的所有事务
    select * from information_schema.innodb_trx
    
    -- 如果有死锁发生,可以通过下面的命令来杀掉当前运行的事务
    kill 258956
    
    • 1
    • 2
    • 3
    • 4
    • 5

    在这里插入图片描述
    执行完对应命令后再次执行查询操作即可看到没有在运行的事务;

    在这里插入图片描述
    在数据库中使用insert into select时,select语句加一个筛选条件,走索引,这样不会出现扫描全表的情况而锁表了。

    如上发生死锁一定要去反复检查业务逻辑里面的sql,检查是否因为书写问题导致锁表等!

    在这里插入图片描述

    注意事项

    • InnoDB的行锁是针对索引加的锁,不是针对记录加的锁。并且该索引不能失效,否则都会从行锁升级为表锁。

    如何检查自己的SQL语句是否使用到了索引?

    • 使用EXPLAIN使用即可:key 显示SQL实际决定查询结果使用的键(索引)。如果没有使用索引,值为NULL

    在这里插入图片描述


    拓展问题

    • 利用到事务就要注意到什么时候事务会失效
    • 利用到索引就要注意到什么时候索引会失效

    二、插入问题

    在执行insert into select的时候对应的字段一定要一一对应,不然插入进去会报错,或者数据执行错误

    CREATE TABLE `bill` (
      `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键',
      `title` varchar(255) DEFAULT NULL,
      `userid` int(11) DEFAULT NULL COMMENT '用户id',
      `money` float(99,2) DEFAULT NULL COMMENT '金额',
      `typeid` int(11) NOT NULL COMMENT '类型 1 收入 2 支出',
      `remark` varchar(255) DEFAULT NULL COMMENT '备注',
      `paywayid` int(11) DEFAULT NULL COMMENT '支付方式',
      `time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '交易时间',
      PRIMARY KEY (`id`) USING BTREE
    ) ENGINE=InnoDB AUTO_INCREMENT=234 DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    CREATE TABLE `bill_test` (
      `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键',
      `title` varchar(255) DEFAULT NULL,
      `userid` int(11) DEFAULT NULL COMMENT '用户id',
      `money` float(99,2) DEFAULT NULL COMMENT '金额',
      `typeid` int(11) NOT NULL COMMENT '类型 1 收入 2 支出',
      `remark` varchar(255) DEFAULT NULL COMMENT '备注',
      `paywayid` int(11) DEFAULT NULL COMMENT '支付方式',
      `time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '交易时间',
      PRIMARY KEY (`id`) USING BTREE
    ) ENGINE=InnoDB AUTO_INCREMENT=234 DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    insert into bill_test (`id`,`title`,`userid`,`money`,`typeid`,`remark`,`paywayid`) 
    select  `id`,`title`,`userid`,`money`,`typeid`,`remark`,`paywayid`  from   bill
    
    • 1
    • 2

    在这里插入图片描述

    因为正常的业务场景肯定不会这么点字段,表与表的对接字段都是足够多的,且表与表的字段不是按顺序对应的,所有要按顺序排好查询出来,再插入,最后测试的时候去数据库检测数据是否正确


    错误案例:此处简单演示一个类型对不上出现的问题

    在这里插入图片描述
    出现Data truncated for column ‘xxx’ at row 1的原因

    MySQL导入文件的时候很容易出现"Data truncated for column ‘xxx’ at row x",其中字符串里的xxx和x是指具体的列和行数.

    有时候,这是因为数据类型的不对应,或者字符串长度不够而造成的.


    📣非常感谢你阅读到这里,如果这篇文章对你有帮助,希望能留下你的点赞👍 关注❤️ 分享👥 留言💬thanks!!!

    📚愿我们奔赴在各自的热爱里!

  • 相关阅读:
    JVM调优,调整JVM参数
    沙盘游戏咨询感悟
    【案例教程】区域气象-大气化学(WRF/Chem)
    vscode远程连接ubuntu
    [python数据处理系列] 深入理解与实践:用Python进行主成分分析(PCA)
    【JAVA-Day31】深入解析冒泡、选择和插入排序在数组排序中的应用
    软件测试 | 接口自动化你不懂?听HttpRunner的作者怎么说
    Redis的Java客户端-Jedis
    【无标题】
    vue 打包更改dist文件名称
  • 原文地址:https://blog.csdn.net/weixin_45393094/article/details/125381805