I am using Stored procedures to do CRUD operations on Mysql DB
DELIMITER $$
CREATE PROCEDURE `transaction_sp` ()
BEGIN
DECLARE exit handler for sqlexception
BEGIN
-- ERROR
ROLLBACK;
END;
DECLARE exit handler for sqlwarning
BEGIN
-- WARNING
ROLLBACK;
END;
START TRANSACTION;
INSERT INTO table_name (id, name, address) values ('1','Test','xpert.com');
SET #LID = LAST_INSERT_ID();
INSERT INTO table_name3 (id, job, responsibilities) values
(#LID,'Sr. Developer','Coding,mentoring etc');
COMMIT;
END
$$
Now, i want that if Second INSERT statement fails then second SQL statement shall not execute and first Insert shall be rolled back.
With my above approach 1st transaction is not rolled back. Do i need to set any flags?
How to handle it? Well explained answer will help here.
Please see my answer below. I believe if you check ##ROWCOUNT or ##Error after each insert you can rollback if there is no rows affected. Sorry if the method I used is wrong.
DELIMITER $$
CREATE PROCEDURE `transaction_sp` ()
BEGIN
DECLARE #nRowCount1 int,
#nRowCount2 int
DECLARE exit handler for sqlexception
BEGIN
-- ERROR
ROLLBACK;
END;
DECLARE exit handler for sqlwarning
BEGIN
-- WARNING
ROLLBACK;
END;
START TRANSACTION;
INSERT INTO table_name (id, name, address) values ('1','Test','xpert.com');
SET #LID = LAST_INSERT_ID();
SET #nRowCount1 = ##ROWCOUNT ;
INSERT INTO table_name3 (id, job, responsibilities) values
(#LID,'Sr. Developer','Coding,mentoring etc');
SET #nRowCount2 =##ROWCOUNT
if(#nRowCount1 <=0 and #nRowCount2<=0)
begin
ROLLBACK ;
end
COMMIT;
END
$$
Related
Assume I have a procedure called prodInner that has an error handler like so
DECLARE EXIT HANDLER FOR SQLEXCEPTION
BEGIN
GET DIAGNOSTICS CONDITION 1
#p1 = RETURNED_SQLSTATE, #p2 = MESSAGE_TEXT;
SELECT #p1 as RETURNED_SQLSTATE, #p2 as MESSAGE_TEXT;
ROLLBACK;
END;
and an outer prod called prodOuter with the same error handler. Say there's an issue when running the inner handler and the sqlexception catches it. Will the outer procedure also "fail" and rollback any and all changes (in addition to changes made in other procedure calls)?
Edit
DROP PROCEDURE TEST_INNER;
CREATE PROCEDURE TEST_INNER()
BEGIN
DECLARE EXIT HANDLER FOR SQLEXCEPTION
BEGIN
ROLLBACK;
RESIGNAL;
END;
START TRANSACTION;
INSERT INTO TEST_TABLE VALUES (1,0);
INSERT INTO TEST_TABLE VALUES(1); # throws an error because two values are required
COMMIT;
end;
CREATE PROCEDURE TEST_OUTER()
BEGIN
DECLARE EXIT HANDLER FOR SQLEXCEPTION
BEGIN
ROLLBACK;
RESIGNAL;
END;
START TRANSACTION;
INSERT INTO TEST_TABLE VALUES (-1,0);
CALL TEST_INNER();
COMMIT;
end;
CALL TEST_OUTER()
CALL TEST_INNER()
Edit 2, is this the best solution?
Statements That Cause an Implicit Commit
Transaction-control and locking statements. BEGIN, LOCK TABLES, SET autocommit = 1 (if the value is not already 1), START TRANSACTION, UNLOCK TABLES.
You may investigate this in details: https://dbfiddle.uk/?rdbms=mysql_8.0&fiddle=76bc26fa4e96b5ea3643aabe8161feea
I think I've figured out the issue but my understanding is very minimal. When the outer procedure is called, a transaction is created. The commit in the inner-procedure however will commit any and all changes in the inner procedure even if the changes in the inner procedure gets rolled back.
I am trying to implement a ROLLBACK functionality on my stored procedure that executes 2 UPDATE queries. I want the second update to only run if the first update was successful. Also if the second update fails, there should be a rollback of the first update statement. I did the below but I need to confirm from you guys if what I wrote is okay. Here is my stored procedure
BEGIN
declare exit handler for sqlexception
BEGIN
rollback;
END;
declare exit handler for sqlwarning
BEGIN
rollback;
END;
START transaction;
FIRST UPDATE
SECOND UPDATE
COMMIT;
SELECT FOUND_ROWS() INTO res;
END
I have a stored procedure which insert data from one database to another. Stored procedure is working fine in mysql but when i call through hibernate, its not working.
DELIMITER $$
CREATE PROCEDURE `INSERTDATA`(stdID BIGINT)
BEGIN
DECLARE exit handler for sqlexception
BEGIN
-- ERROR
ROLLBACK;
END;
DECLARE exit handler for sqlwarning
BEGIN
-- WARNING
ROLLBACK;
END;
START TRANSACTION;
INSERT INTO `db2`.`std`
SELECT * FROM stdDetails WHERE studID=stdID;
COMMIT;
END
// working fine if i do this
call INSERTDATA(1);
But
Query procQry = session.createSQLQuery( "CALL ARCHIVEEVENTDATA(?)");
procQry.setParameter(0,examEventID);
procQry.executeUpdate();
transaction.commit();
Not working for me :(
Note : Both databases are on same server
Is it possible to roll back automatically if any error occurs on a list of mysql commands?
for example something along the lines of:
begin transaction;
insert into myTable values1 ...
insert into myTable values2 ...; -- will throw an error
commit;
now, on execute i want the whole transaction to fail, and therefore i should NOT see values1 in myTable.
but unfortunately the table is being pupulated with values1 even though the transaction has errors.
any ideas how i make it to roll back? (again, on any error)?
EDIT - changed from DDL to standard SQL
You can use 13.6.7.2. DECLARE ... HANDLER Syntax in the following way:
DELIMITER $$
CREATE PROCEDURE `sp_fail`()
BEGIN
DECLARE `_rollback` BOOL DEFAULT 0;
DECLARE CONTINUE HANDLER FOR SQLEXCEPTION SET `_rollback` = 1;
START TRANSACTION;
INSERT INTO `tablea` (`date`) VALUES (NOW());
INSERT INTO `tableb` (`date`) VALUES (NOW());
INSERT INTO `tablec` (`date`) VALUES (NOW()); -- FAIL
IF `_rollback` THEN
ROLLBACK;
ELSE
COMMIT;
END IF;
END$$
DELIMITER ;
For a complete example, check the following SQL Fiddle.
You could use EXIT HANDLER if you for example need to SIGNAL a specific SQL EXCEPTION in your code. For instance:
DELIMITER $$
CREATE PROCEDURE `sp_fail`()
BEGIN
DECLARE EXIT HANDLER FOR SQLEXCEPTION
BEGIN
ROLLBACK; -- rollback any changes made in the transaction
RESIGNAL; -- raise again the sql exception to the caller
END;
START TRANSACTION;
insert into myTable values1 ...
IF fail_condition_meet THEN
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'Custom error detected.', MYSQL_ERRNO = 2000;
END IF;
insert into myTable values2 ... -- this will not be executed
COMMIT; -- this will not be executed
END$$
DELIMITER ;
The above solution are good but to make it even simpler
DELIMITER $$
CREATE PROCEDURE `sp_fail`()
BEGIN
DECLARE EXIT HANDLER FOR SQLEXCEPTION
BEGIN
ROLLBACK; -- rollback any error in the transaction
END;
START TRANSACTION;
insert into myTable values1 ...
insert into myTable values2 ... -- Fails
COMMIT; -- this will not be executed
END$$
DELIMITER ;
Can someone tell me if it is possible to call another procedure from within a procedure and if any part of either procedure fails, roll everything back?
If this is possible, can someone please show me a tiny example of how this would be implemented?
EDIT: Procedure "b" fails but procedure "a" still inserts a row into table "a". It's my understanding that if any part of the insert fails that everything (both inserts) is rolled back which is not happening here. The questions is why not?
Procedure "a"
BEGIN
DECLARE b INT DEFAULT 0;
DECLARE EXIT HANDLER FOR SQLWARNING ROLLBACK;
DECLARE EXIT HANDLER FOR SQLEXCEPTION ROLLBACK;
START TRANSACTION;
INSERT INTO a(a)
VALUES(iA);
CALL b(iB,LAST_INSERT_ID(),#b);
SELECT #b INTO b;
IF b !=1 THEN
ROLLBACK;
ELSE
COMMIT;
END IF;
END
Procedure "b"
BEGIN
DECLARE b INT DEFAULT 0;
DECLARE EXIT HANDLER FOR SQLWARNING ROLLBACK;
DECLARE EXIT HANDLER FOR SQLEXCEPTION ROLLBACK;
START TRANSACTION;
INSERT INTO b VALUES(iB,id);
SET b=1;
COMMIT;
END;
You will need to handle transactions in both procedures, but the proc that is calling the other, should check for the return value and rollback it's transactions based on that. Here is an example of the inner proc:
How to detect a rollback in MySQL stored procedure?
you would then check for p_return_code and do a rollback of the parent transaction.
EDIT:
What I think is happening is that inner SP COMMIT or ROLLBACK affect outer SP TRANSACTION. This code works for me, if inner SP fail it rolls back both insert statements. First call to ab() works, new user record gets inserted and new game record gets inserted, if we remove record from the games table and run ab() again, because user id already exists it rolls back games table insert:
create procedure ab()
BEGIN
START TRANSACTION;
INSERT INTO games (title) VALUES ('bad game');
CALL ba(#ret);
IF #ret!=0 THEN
ROLLBACK;
ELSE
COMMIT;
END IF;
END;
create procedure ba(OUT return_value tinyint unsigned)
BEGIN
DECLARE exit handler for sqlexception
BEGIN
set return_value = 1;
END;
INSERT INTO users (id) VALUES(1);
set return_value = 0;
END;
To test use call ab();