什么是错误缓冲堆栈呢? 举个很简单的例子,比如执行下面一条语句:
mysql> insert into t_datetime values(2,'4','5');
error 1292 (22007): incorrect datetime value: '4' for column 'log_time' at row 1
上面1292这个代码指示的错误信息保存在哪里呢? 就保存在错误缓冲堆栈, 在mysql里面叫 diagnostics area。 关于这个概念,一直在mysql5.7才得到确定的更新。
在mysql5.5之前,想要得到这块区域的数据,就只能通过c的api来获取,从sql层面是无法检索到的。mysql5.5 先推出了这个概念。
在mysql5.6发布后,不但可以检索这块区域,而且还可以重新封装,得到我们想要的数据。但是这块区域依然是只能保存一次错误代码,很容易被重置。
在mysql5.7发布后,可以更加容易的检索这块区域,而且把这里的数据放到一个stack里,重置的条件更加宽松。以下举例子来说明。
示例表结构如下,
create table `t_datetime` (
`id` int(11) not null,
`log_time` timestamp not null default current_timestamp on update current_timestamp,
`end_time` datetime not null,
primary key (`id`)
) engine=innodb default charset=utf8;
用来记录错误数据的日志表。
create table tb_log (errorno int,errortext text,error_timestamp datetime);
在mysql5.6环境下,我要这样写一段繁杂的代码来获取错误信息。
delimiter $$
use `new_feature`$$
drop procedure if exists `sp_do_insert`$$
create definer=`root`@`localhost` procedure `sp_do_insert`(
in f_id int,
in f_log_time varchar(255),
in f_end_time varchar(255)
)
begin
declare done1 tinyint default 0; -- 保存是否发生异常的布尔值。
declare i tinyint default 1;
declare v_errcount int default 0; -- 获取一次错误数据条数
declare v_errno int default 0; -- 获取错误代码
declare v_msg text; -- 获取错误详细信息
declare continue handler for sqlexception -- 定义一个异常处理块
begin
set done1 = 1; -- 发生异常,设置为1.
get diagnostics v_errcount = number;
set v_msg = '';
while i <= v_errcount
do
get diagnostics condition i
v_errno = mysql_errno, v_msg = message_text;
set @stmt = concat('select ',v_errno,',"',v_msg,'","',now(),'" into @errno',i,',@msg',i,',
@log_timestamp',i,';');
prepare s1 from @stmt;
execute s1;
set i = i + 1;
end while;
drop prepare s1;
end;
insert into t_datetime (id,log_time,end_time) values(f_id,f_log_time,f_end_time);
if done1 = 1 then -- 把错误数据记录到表tb_log里。
set i = 1;
while i <= v_errcount
do
set @stmt = concat('insert into tb_log ');
set @stmt = concat(@stmt,' select @errno',i,',@msg',i,',@log_timestamp');
prepare s1 from @stmt;
execute s1;
set i = i + 1;
end while;
drop prepare s1;
end if;
end$$
delimiter ;
mysql5.7发布后,现在可以精简我的代码了。
delimiter $$
use `new_feature`$$
drop procedure if exists `sp_do_insert`$$
create definer=`root`@`localhost` procedure `sp_do_insert`(
in f_id int,
in f_log_time varchar(255),
in f_end_time varchar(255)
)
begin
declare i tinyint default 1;
declare v_errcount int default 0; -- 获取一次错误数据条数
declare v_errno int default 0; -- 获取错误代码
declare v_msg text; -- 获取错误详细信息
declare continue handler for sqlexception -- 定义一个异常处理块
begin
get stacked diagnostics v_errcount = number;
while i <= v_errcount
do
get stacked diagnostics condition i -- 把错误数据分别保存在变量里
v_errno = mysql_errno, v_msg = message_text;
insert into tb_log values (v_errno,v_msg,now());
set i = i + 1;
end while;
end;
insert into t_datetime (id,log_time,end_time) values(f_id,f_log_time,f_end_time);
end$$
delimiter ;
现在来执行下:
mysql> call sp_do_insert(2,'4','5');
query ok, 1 row affected (0.01 sec)
来检索表tb_log的数据。
mysql> select * from tb_log\g
*************************** 1. row ***************************
errorno: 1265
errortext: data truncated for column 'log_time' at row 1
error_timestamp: 2015-11-17 11:53:10
*************************** 2. row ***************************
errorno: 1265
errortext: data truncated for column 'end_time' at row 1
error_timestamp: 2015-11-17 11:53:10
*************************** 3. row ***************************
errorno: 1062
errortext: duplicate entry '2' for key 'primary'
error_timestamp: 2015-11-17 11:53:10
3 rows in set (0.00 sec)
总结下, 如果先用到diagnostics area, 最好是在存储过程里面写代码封装sql。
以上就是mysql5.7的错误堆栈缓冲_mysql的内容。