简体   繁体   中英

How to use a transaction in a stored procedure?

I have an SQL script that I need to convert to a parameterized stored procedure. I've only written simple functions in the past, never a complex transactional query with parameters.

Any help is greatly appreciated - simplified queries below. This script could really be anything containing a transaction and some user inputs.

-- transaction ensures i can clean up a mess, if one happens
begin;

-- parameters for the script; currently set manually before execution
set @parent_id := 123;
set @identifier := 'someid';

-- insert some row with user-specified values
insert into users (field1, field2) values (@parent_id, @identifier);

-- get the new id
set @user_id := last_insert_id();

-- do another insert
insert into usersmeta (user_id, field1, field2) values (@user_id, 1, 2);

-- if no errors happened yet, commit transaction
commit;

-- "return value"; some select query (could be 1 or many rows)
select users.id userid, usersmeta metaid
from users
join usersmeta on usersmeta.user_id = users.id;

I started with but then I pretty much got stuck. I'm especially concerned with ensuring errors, in the event they occur, are somehow made visible to the calling code

delimiter ;; 
CREATE PROCEDURE mytask(IN parent_id INT(11), IN identifier VARCHAR(200)) 
BEGIN 
        SET @query = ??? 
        PREPARE q FROM @query; 
        EXECUTE q; 
        DEALLOCATE PREPARE q; 
END;; 
delimiter ; 

It took a good amount of research, trial, and error, but I think I arrived at a pretty good solution.

DELIMITER //

CREATE PROCEDURE my_procedure (IN parent_id int, IN identifier varchar(255), OUT out_user_id int)
BEGIN

  -- local variable, set later after user is created
  DECLARE user_id int;

  -- rollback transaction and bubble up errors if something bad happens
  DECLARE exit handler FOR SQLEXCEPTION, SQLWARNING
  BEGIN
    ROLLBACK;
    RESIGNAL;
  END;

  START TRANSACTION;

  -- insert some row with user-specified values
  INSERT INTO users (field1, field2) values (parent_id, identifier);

  -- get the new id
  SET user_id = last_insert_id();

  -- do another insert
  INSERT INTO usersmeta (user_id, field1, field2) values (user_id, 1, 2);

  -- if no errors happened yet, commit transaction
  COMMIT;

  -- return
  SELECT user_id INTO out_user_id;

END //

DELIMITER ;

I can use it like this

-- run the procedure
CALL my_procedure(123, 'some_id', @user_id);

-- get the "return" value
SELECT @user_id as user_id;

This is definitely the most complex stored procedure I've written. If anyone sees an area for improvement, I'd be happy to learn how I can make it better.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM