【问题标题】:MySQL Stored Procedures with detail table and transactions带有明细表和事务的 MySQL 存储过程
【发布时间】:2014-09-24 23:25:16
【问题描述】:

我正在处理一个相对较大的(对我而言)存储过程,它负责在发生“移动”时维护库存值。

我最初在 PHP 中进行了所有检查和插入,但我觉得数据库中需要发生的事情的数量通过将其放在存储过程中并拒绝对这些表的 INSERT/UPDATE 权限使其更可控.

抛开历史不谈,我很好奇是否有一种方法可以为存储过程运行准备好的语句,在该语句中我可以传递多个值,这些值将被插入到详细信息表中。

例如,假设我想将以下数据插入到父子记录中。

"ACME", "TNT", 100
"ACME", "Anvil", 5

父记录将包含ACME,子记录将包含TNT, 100Anvil, 5 的详细信息。

是否有可能以某种方式将这些数据传递到单个存储过程中?

我希望一次性完成此操作的原因是,假设我们没有足够的 TNT 可用,我不希望插入原始父记录,除非可以进行整个交易。

【问题讨论】:

  • 如果您已经有了可以工作的代码,为什么不直接通过 php 开始/提交交易?
  • 我想确保来自不同应用程序的调用执行某些检查以维护数据完整性。如果提供给存储过程的数据不满足客户标志/要求,我可以轻松抛出错误并回滚事务。这取决于在 PHP/Java/等中实现它的人。
  • 好吧,如果你想在可重用代码之上构建,我认为通常使用服务层而不是在数据库中构建应用程序。然后你可以在 JSON 或 XML 中传递它没有问题。
  • 确实如此。我仍然会至少将其中的一部分外包给存储过程,以便删除对重要表的直接访问,但我可以在服务层进行检查和错误。

标签: mysql sql stored-procedures


【解决方案1】:

连接发送到存储过程的数据会起作用吗?我无法想象一次向数据库发送超过 1000 条详细信息行。

do_movement('ACME','2:TNT,100||Anvil,5'); 前面的 2 表示期望的细节数量,可能有助于错误捕获。只是一个想法。

这样代码将负责格式化,但我可以输出 SQLEXCEPTIONS 并让所有事情都发生在一个真正的事务中。

大量借鉴这篇文章:MySQL Split Comma Separated String Into Temp Table

使用 SPLIT_STR 函数来自(在上一篇文章中也引用过):http://blog.fedecarg.com/2009/02/22/mysql-split-string-function/

CREATE FUNCTION SPLIT_STR(
  x VARCHAR(255),
  delim VARCHAR(12),
  pos INT
)
RETURNS VARCHAR(255)
RETURN REPLACE(SUBSTRING(SUBSTRING_INDEX(x, delim, pos),
       LENGTH(SUBSTRING_INDEX(x, delim, pos -1)) + 1),
       delim, '');

然后是我解析N:s1|s2|..|sN 并检查的功能。

如果我有 N:s1,a1|s2,a2|..|sN,aN 之类的东西,我可以轻松地再次调用 SPLIT_STR

BEGIN
    DECLARE defined_quantity INT;
    IF serial_numbers REGEXP '^[^0]{0,}[[:digit:]]+:.*$' = TRUE THEN -- check that we are indeed at least starting properly formatted.
        SET defined_quantity = CONVERT(LEFT(serial_numbers,LOCATE(':',serial_numbers)-1), UNSIGNED);
        IF defined_quantity <= 0 THEN
            SIGNAL SQLSTATE '45006'
                SET MESSAGE_TEXT = 'The quantity defined with the serial number list is <= 0.';
        END IF;
        SET serial_numbers = RIGHT(serial_numbers,LENGTH(serial_numbers) - LOCATE(':',@serial_numbers));
        BEGIN
            DECLARE a INT Default 0 ;
            DECLARE str VARCHAR(255);
            DECLARE q INT;
            simple_loop: LOOP
                SET a=a+1;
                SET str=TRIM(SPLIT_STR(serial_numbers,"|",a));
                IF str='' THEN
                    SET a=a-1; -- we ignore the last increment
                    LEAVE simple_loop;
                END IF;
                #Do Inserts into temp table here with str going into the row
                INSERT INTO transaction_detail (transaction_id, serial_number,created_at,updated_at) VALUES(transaction_id, str,NOW(),NOW());
            END LOOP simple_loop;
            SELECT a, defined_quantity, quantity;
            IF a <> defined_quantity OR a <> quantity OR defined_quantity <> quantity THEN
                SIGNAL SQLSTATE '45007'
                    SET MESSAGE_TEXT = 'The quantities do not match for the serial numbers provided.';
            END IF;
        END;
    ELSE
        SIGNAL SQLSTATE '45005'
            SET MESSAGE_TEXT = 'The serial number formatted list is not properly formatted.  Please provide in "n:s1|s2|s3|...|sn" format.';
    END IF;
END;

【讨论】:

    猜你喜欢
    • 2012-04-15
    • 2021-06-02
    • 1970-01-01
    • 1970-01-01
    • 2015-03-24
    • 2012-09-26
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多