技术分享 | MySQL 在批量插入时捕捉错误信息「终于解决」

技术分享 | MySQL 在批量插入时捕捉错误信息「终于解决」技术分享 | MySQL 在批量插入时捕捉错误信息

原创: 杨涛涛

背景

本篇文章来源于今天客户问的一个问题。

问题大概意思是:我正在从 Oracle 迁移到 MySQL,数据已经转换为单纯的 INSERT 语句。由于语句很多,每次导入的时候不知道怎么定位到错误的语句。 如果 INSERT 语句少也就罢了,我可以手工看,不过 INSERT 语句很多,我怎么定位到是哪些语句出错了,我好改正呢?总不能每次遇到的错误的时候改一下,再重新运行继续改正吧?有没有简单点的方法。

其实 MySQL 自身就有错误诊断区域,如果能好好利用,则事半功倍。

演示

下面我来简单说下怎么使用错误诊断区域

比如说我要插入的表结构为 n3,保存错误信息的日志表为 error_log 两个表结构如下:

-- tables definition.
[ytt]>create table n3 (id int not null, id2 int generated always as ((mod(id,10))));
Query OK, 0 rows affected (0.04 sec)
[ytt]>create table error_log (sqltext text, error_no int unsigned, error_message text);
Query OK, 0 rows affected (0.04 sec)

假设插入的语句,为了演示,我这里仅仅简单写了 8 条语句。

-- statements body.
set @a1 = "INSERT INTO n3 (id) VALUES(100)";
set @a2 = "INSERT INTO n3 (id) VALUES('test')";
set @a3 = "INSERT INTO n3 (id) VALUES('test123')";
set @a4 = "INSERT INTO n3 (id) VALUES('123test')";
set @a5 = "INSERT INTO n3 (id) VALUES(200)";
set @a6 = "INSERT INTO n3 (id) VALUES(500)";
set @a7 = "INSERT INTO n3 (id) VALUES(null)";
set @a8 = "INSERT INTO n3 (id) VALUES(10000000000000)";

MySQL 的错误代码很多,不过总体归为三类:

  • sqlwarning SQLSTATE 代码开始为 ’01’
  • not found SQLSTATE 代码开始为 ’02’
  • sqlexception SQLSTATE 代码开始非 ’00’,’01’,’02’ 的所有错误代码。

为了简单方便,我们写这些代码到存储过程里。以下为示例存储过程。

-- stored routines body.
drop procedure if exists sp_insert_simple;
delimiter ||
create procedure sp_insert_simple()
l1:begin
 DECLARE i,j TINYINT DEFAULT 1; -- loop counter.
 DECLARE v_errcount,v_errno INT DEFAULT 0; -- error count and error number.
 DECLARE v_msg TEXT; -- error details.
 declare v_sql json; -- store statements list.
 declare v_sql_keys varchar(100); -- array index.
 declare v_sql_length int unsigned; -- array length.
 -- Handler declare.
 DECLARE CONTINUE HANDLER FOR SQLEXCEPTION,SQLWARNING,NOT FOUND -- exception in mysql routines.
 l2:BEGIN
 get stacked diagnostics v_errcount = number;
 set j = 1;
 WHILE j <= v_errcount
 do
 GET stacked DIAGNOSTICS CONDITION j v_errno = MYSQL_ERRNO, v_msg = MESSAGE_TEXT;
 -- record error messages into table.
 INSERT INTO error_log(sqltext,error_no,error_message) VALUES (@sqltext, v_errno,v_msg);
 SET j = j + 1;
 END WHILE;
 end;
 -- sample statements array.
 set v_sql = '{
 "a1": "INSERT INTO n3 (id) VALUES(100)",
 "a2": "INSERT INTO n3 (id) VALUES(''test'')",
 "a3": "INSERT INTO n3 (id) VALUES(''test123'')",
 "a4": "INSERT INTO n3 (id) VALUES(''123test'')",
 "a5": "INSERT INTO n3 (id) VALUES(200)",
 "a6": "INSERT INTO n3 (id) VALUES(500)",
 "a7": "INSERT INTO n3 (id) VALUES(null)",
 "a8": "INSERT INTO n3 (id) VALUES(10000000000000)"
}';
 set i = 1;
 set v_sql_length = json_length(v_sql);
 while i <=v_sql_length do
 set v_sql_keys = concat('$.a',i);
 set @sqltext = replace(json_extract(v_sql,v_sql_keys),'"','');
 prepare s1 from @sqltext;
 execute s1;
 set i = i + 1;
 end while;
 drop prepare s1;
 -- invoke procedure.
 -- call sp_insert_simple;
end;
||
delimiter ;

我们来调用这个存储过程看下结果。

[(none)]>use ytt
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A
Database changed
[ytt]>call sp_insert_simple;
Query OK, 0 rows affected (0.05 sec)

表N3的结果。

[ytt]>select * from n3;
+-----+------+
| id | id2 |
+-----+------+
| 100 | 0 |
| 200 | 0 |
| 500 | 0 |
+-----+------+
3 rows in set (0.00 sec)

错误日志记录了所有错误的语句。

[ytt]>select * from error_log;
+--------------------------------------------+----------+-------------------------------------------------------------+
| sqltext | error_no | error_message |
+--------------------------------------------+----------+-------------------------------------------------------------+
| INSERT INTO n3 (id) VALUES('test') | 1366 | Incorrect integer value: 'test' for column 'id' at row 1 |
| INSERT INTO n3 (id) VALUES('test123') | 1366 | Incorrect integer value: 'test123' for column 'id' at row 1 |
| INSERT INTO n3 (id) VALUES('123test') | 1265 | Data truncated for column 'id' at row 1 |
| INSERT INTO n3 (id) VALUES(null) | 1048 | Column 'id' cannot be null |
| INSERT INTO n3 (id) VALUES(10000000000000) | 1264 | Out of range value for column 'id' at row 1 |
+--------------------------------------------+----------+-------------------------------------------------------------+
5 rows in set (0.00 sec)

其实这个问题如果用 Python 或 PHP 等外部语言来说,将会更简单,思路差不多。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
转载请注明出处: https://daima100.com/11758.html

(0)

相关推荐

  • Python List长度求取方法

    Python List长度求取方法Python中的List是一种灵活而强大的序列数据类型,存储多个元素并且可以进行索引和切片。计算List的长度是常见的操作,可以使用Python内置函数len()来获得List的长度。例如:

    2024-01-06
    116
  • mysql性能优化总结(三)[通俗易懂]

    mysql性能优化总结(三)[通俗易懂]mysql体系结构 插件式存储引擎,将数据的查询和存储相分离.每一款存储引擎都有各自的优缺点.可以灵活选用 架构: 客户端 -> mysql服务层 -> 存储引擎层 存储引擎是针对表,不是针对库,同…

    2023-03-19
    158
  • Python词频统计代码

    Python词频统计代码a href=”https://beian.miit.gov.cn/”苏ICP备2023018380号-1/a Copyright www.python100.com .Some Rights Reserved.

    2024-04-30
    73
  • 用Python的List Comprehension提高代码效率

    用Python的List Comprehension提高代码效率List Comprehension是Python中的一种语法特性,它可以让我们使用简单而又优雅的方式来创建列表。

    2024-07-02
    74
  • 云计算——虚拟化技术「建议收藏」

    云计算——虚拟化技术「建议收藏」绿色节能提高了IT运维效率,系统管理人员减少操作系统和硬件的解耦虚拟化的本质:虚拟化中的几个重要概念:

    2023-07-10
    149
  • JS 中10个命名最糟糕但超实用的 API[通俗易懂]

    JS 中10个命名最糟糕但超实用的 API[通俗易懂]你觉得 JS 里命名最糟糕的 API 有哪些? 前几天贺老聊到这个话题,快一起来看看这些容易搞混的东西都有哪些吧🕵️‍♂️

    2023-03-02
    165
  • MySQL事务隔离级别和MVCC

    MySQL事务隔离级别和MVCCMySQL是一个服务器/客户端架构的软件,对于同一个服务器来说,可以有若干个客户端与之连接,每个客户端与服务器连接上之后,就可以称之为一个会话(Session)。我们可以同时在不同的会话里输入各种语句,这些语句可以作为事务的一部分进行处理。不同的会话可以同时发送请求,也就是说服…

    2023-04-03
    157
  • Python正则表达式的实际应用

    Python正则表达式的实际应用正则表达式是一种用来描述、匹配一定模式文本的模式字符串。在文本处理、自然语言处理、网络爬虫等领域都有广泛应用,是Python中重要的文本处理工具之一。本文将从常用正则表达式用法、特殊字符、re模块常用方法等多个方面对Python中正则表达式的实际应用进行详细阐述。

    2023-12-24
    96

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注