我的应用程序通过存储过程记录几个MySQL表中每个http请求的详细信息,该存储过程向应用程序返回唯一的请求ID。
CALL http_req('ip', 'url', 'method', 'timestamp', @error, @request_id);
现在我还要将所有http请求标头记录到一个表中,每个标头都在一个单独的行中:
CREATE TABLE `http_header` (
`id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
`request_id` INT(10) UNSIGNED NOT NULL,
`name` VARCHAR(255) NOT NULL COLLATE 'utf8_unicode_ci',
`value` VARCHAR(255) NOT NULL COLLATE 'utf8_unicode_ci',
PRIMARY KEY (`id`))
问题是每个客户端都有不同数量和类型的标头。我还没有找到一种方法将所有标题详细信息传递给我的存储过程,然后将它们插入上表。
目前我必须在存储过程调用之后从我的应用程序生成并执行第二个插入查询以保存标题:
INSERT INTO http_header (request_id, name, value)
VALUES (20153, 'cache-control', 'max-age=0'),
(20153, 'accept', 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8'),
(20153, 'accept-encoding', 'gzip,deflate,sdch');
是否可以保存第二个查询并从存储过程中插入标题?比如将所有头文件作为单个字符串传递并在存储过程中解析它?
答案 0 :(得分:0)
是的,有可能。 MySQL确实支持足够的流控制结构(REPEAT
,IF
)和字符串处理(LOCATE()
,SUBSTRING()
),以允许拆分数据库中的标头字符串。这是一个非常简单的例子:
CREATE PROCEDURE http_req(IN ip CHAR(12), IN url VARCHAR(512), IN method CHAR(8), IN ts DATETIME, IN headers TEXT, OUT err INT, OUT request_id INT)
BEGIN
DECLARE loc INT;
DECLARE hloc INT;
DECLARE hdr TEXT DEFAULT NULL;
DECLARE hval TEXT DEFAULT NULL;
DECLARE s TEXT DEFAULT NULL;
START TRANSACTION;
INSERT INTO http_requests VALUES (NULL,INET_ATON(ip), url, method, ts);
SELECT last_insert_id() INTO request_id;
REPEAT
SET loc=LOCATE("\n",headers);
IF (loc = 0) THEN
SET s=headers;
ELSE
SET s=SUBSTRING(headers,1,loc-1);
SET headers=SUBSTRING(headers,loc+1);
END IF;
SET hloc=LOCATE(':',s);
IF (hloc = 0) THEN
SET hdr=s;
SET hval='';
ELSE
SET hdr=SUBSTRING(s,1,hloc-1);
SET hval=SUBSTRING(s,hloc+1);
END IF;
INSERT INTO http_header VALUES (null,request_id,hdr,hval);
UNTIL (loc=0) END REPEAT;
COMMIT;
END
此代码存在一些明显的问题;如果它们包含换行符(\n
),则标题将被错误存储。此外,没有错误管理(例如,err
返回值未正确填充;没有回滚)。解决这些问题已经留给了读者;)