MySQL Stored Procedure Transaction Management and mysql Stored Procedure transaction

Source: Internet
Author: User
Tags savepoint

MySQL Stored Procedure Transaction Management and mysql Stored Procedure transaction

 

ACID: Atomic, Consistent, Isolated, Durable
A storage program provides an excellent mechanism to define, encapsulate, and manage transactions.

1. MySQL transaction support 
MySQL transaction support is not bound to the MySQL server itself, but related to the storage engine:
MyISAM: transactions are not supported. It is used by read-only programs to improve performance. InnoDB: supports ACID transactions, row-level locks, and concurrent Berkeley DB. transactions are supported.
 
Isolation level:
The isolation level determines the impact of transactions in one session on another session, the operations of concurrent sessions on the database, and the consistency of data seen in one session.
The ANSI standard defines four isolation levels. MySQL InnoDB supports:
Read uncommitted: the lowest level of isolation, usually called dirty read, which allows a transaction to READ data that has not been committed, which may improve performance, however, dirty read may not be the read committed we want: in a transaction, only commit records are allowed to be visible. If the select statement in the session is still being queried, another session will insert a record at this time, the newly added data is invisible to the repeatable read: after a transaction starts, the changes made by other sessions to the database are invisible to the competent service until the transaction commit or rollback. The same result is returned when the select statement is repeated in a transaction, unless the database is updated in the event service. SERIALIZABLE: isolation at the highest level, which only allows serial execution of transactions. To this end, the database locks the records read by each row. Other sessions cannot modify the data until the previous transaction ends. The lock is released only when the transaction is committed or canceled.
You can use the following statement to set the MySQL session isolation level:
SET TRANSACTION ISOLATION LEVEL {READ UNCOMMITTED | READ COMMITTED | REPEATABLE READ | SERIALIZABLE}  
The default isolation level of MySQL is repeatable read. Be careful when setting the isolation level to read uncommitted or SERIALIZABLE. read uncommitted will cause serious data integrity problems, SERIALIZABLE causes performance problems and increases the chance of deadlock.

Transaction Management statement:
Start transaction: START the TRANSACTION. autocommit is set to 0. If a TRANSACTION is already running, a hidden COMMIT is triggered: COMMIT the TRANSACTION, save the changes, and release the lock ROLLBACK: roll back all changes made TO the database by the transaction, and end the transaction. Release the SAVEPOINT savepoint_name lock: Create a savepoint identifier to rollback to savepoint savepoint_name: roll back to all changes made to the database starting from savepoint_name. In this way, part of the TRANSACTION can be rolled back to ensure that a subset of the changes is committed. set transaction: allow setting the isolation level of the transaction lock tables: allow explicit locking of one or more TABLES to implicitly close the currently opened transactions. We recommend that you explicitly commit or rollback the transactions before executing the lock tables statement. We generally do not use lock tables in transaction code.

  

2. Define transactions 
By default, MySQL runs a COMMIT statement after each SQL statement is executed to effectively separate each statement into a transaction.
In complex application scenarios, this method cannot meet the requirements.
To open a transaction and allow execution of multiple statements before COMMIT and ROLLBACK, we need to do the following two steps:
Set the autocommit attribute of MySQL to 0. The default value is 1. Use the start transaction statement to explicitly open a TRANSACTION.
If a TRANSACTION has been opened, SET autocommit = 0 does not work, because start transaction implicitly commits all the current changes in the session, ends the existing TRANSACTION, and opens a new TRANSACTION.

Example of a stored procedure using the set autocommit statement:
CREATE PROCEDURE tfer_funds      (from_account int, to_account int, tfer_amount numeric(10,2))  BEGIN      SET autocommit=0;        UPDATE account_balance SET balance=balance-tfer_amount WHERE account_id=from_account;        UPDATE account_balance SET balance=balance+tfer_amount WHERE account_id=to_account;        COMMIT;  END;  
Example of opening a transaction using start transaciton:
CREATE PROCEDURE tfer_funds      (from_account int, to_account int, tfer_amount numeric(10,2))  BEGIN      START TRANSACTION;        UPDATE account_balance SET balance=balance-tfer_amount WHERE account_id=from_account;        UPDATE account_balance SET balance=balance+tfer_amount WHERE account_id=to_account;        COMMIT;  END;  
Generally, a transaction is completed only when the COMMIT or ROLLBACK statement is executed. However, some DDL statements may implicitly trigger the COMMIT. Therefore, you should use as few or pay attention to the following in the transaction:
ALTER FUNCTION  ALTER PROCEDURE  ALTER TABLE  BEGIN  CREATE DATABASE  CREATE FUNCTION  CREATE INDEX  CREATE PROCEDURE  CREATE TABLE  DROP DATABASE  DROP FUNCTION  DROP INDEX  DROP PROCEDURE  DROP TABLE  UNLOCK TABLES  LOAD MASTER DATA  LOCK TABLES  RENAME TABLE  TRUNCATE TABLE  SET AUTOCOMMIT=1  START TRANSACTION  

  

3. Use Savepoint 
The use of savepoint rollback inevitably consumes some performance, and can be rewritten with IF
One of the good scenarios of savepoint is "nested transactions". You may want the program to execute a small transaction, but do not want to roll back a larger transaction:
CREATE PROCEDURE nested_tfer_funds      (in_from_acct   INTEGER,       in_to_acct     INTEGER,       in_tfer_amount DECIMAL(8,2))  BEGIN      DECLARE txn_error INTEGER DEFAULT 0;        DECLARE CONTINUE HANDLER FOR SQLEXCEPTION BEGIN          SET txn_error=1;      END        SAVEPINT savepint_tfer;        UPDATE account_balance         SET balance=balance-in_tfer_amount       WHERE account_id=in_from_acct;        IF txn_error THEN          ROLLBACK TO savepoint_tfer;          SELECT 'Transfer aborted';      ELSE          UPDATE account_balance             SET balance=balance+in_tfer_amount           WHERE account_id=in_to_acct;            IF txn_error THEN              ROLLBACK TO savepoint_tfer;              SELECT 'Transfer aborted';            END IF:      END IF;  END;  

  

4. Transactions and locks 
The ACID attribute of a transaction can only be achieved by limiting the synchronous changes to the database, and thus by locking the modified data.
The lock is released only when the transaction triggers a COMMIT or ROLLBACK statement.
The disadvantage is that the subsequent transactions must wait until the previous transactions are completed before execution can begin, and the throughput decreases as the wait time for the lock to be released increases.
MySQL/InnoDB minimizes lock competition through row-level locks. In this way, there is no limit to modifying the data of other rows in the same table, and the read data can never be waited.
You can use the for update or lock in share mode statement IN the SELECT statement to add row-level locks.
SELECT select_statement options [FOR UPDATE|LOCK IN SHARE MODE]  

 

For update locks the rows returned by the SELECT statement. Other SELECT and DML statements must wait until the transaction of the SELECT statement is completed.
The lock in share mode is the same as for update, but the SELECT statement of other sessions can be executed and the share mode lock can be obtained.

Deadlock:
A deadlock occurs when two transactions wait for each other to release the lock.
When MySQL/InnoDB detects a deadlock, it forces a transaction rollback and triggers an error message.
For InnoDB, the selected rollback transaction is the transaction with the least work done (with the least modified rows)
mysql > CALL tfer_funds(1,2,300);  ERROR 1213 (40001): Deadlock found when trying to get lock; try restarting transaction  
Deadlock may occur in any database system, but it is less likely for Row-Level Lock databases such as MySQL and InnoDB.
You can use consistent sequence to lock the row or table and keep the transaction as short as possible to reduce the deadlock frequency.
If the deadlock is not easy to debug, you can add some logic to your program to handle the deadlock and retry the transaction, but it is difficult to maintain this part of the code after it is too much.
Therefore, the better way to avoid deadlocks is to add row-level locks in a certain order before making any modifications, so as to avoid deadlocks:
CREATE PROCEDURE tfer_funds3      (from_account INT, to_account INT, tfer_amount NUMERIC(10,2))  BEGIN      DECLARE local_account_id INT;      DECLARE lock_cursor CURSOR FOR          SELECT account_id            FROM account_balance           WHERE account_id IN (from_account, to_account)           ORDER BY account_id             FOR UPDATE;        START TRANSACTION;        OPEN lock_cursor;      FETCH lock_cursor INTO local_account_id;        UPDATE account_balance         SET balance=balance-tfer_amount       WHERE account_id=from_account;        UPDATE account_balance         SET balance=balance+tfer_amount       WHERE account_id=to_account;        CLOSE lock_cursor;        COMMIT;  END;  
Set the deadlock ttl: innodb_lock_wait_timeout. The default value is 50 seconds.
If you use both InnoDB and non-InnoDB tables in a transaction, MySQL cannot detect a deadlock and throws the "lock wait timeuot" 1205 error.

Optimistic and pessimistic locking strategies:
Pessimistic lock: these rows are locked when data is read, and other updates to these rows can continue until the pessimistic lock ends.
Optimistic: No lock is applied when reading data. Check whether the data has been updated when updating. If yes, cancel the current update.
We usually choose an optimistic lock when the waiting time of the pessimistic lock is too long and it cannot be accepted.
Pessimistic lock example:
CREATE PROCEDURE tfer_funds         (from_account INT, to_account INT,tfer_amount NUMERIC(10,2),          OUT status INT, OUT message VARCHAR(30))  BEGIN      DECLARE from_account_balance NUMERIC(10,2);        START TRANSACTION;          SELECT balance        INTO from_account_balance        FROM account_balance       WHERE account_id=from_account         FOR UPDATE;        IF from_account_balance>=tfer_amount THEN             UPDATE account_balance              SET balance=balance-tfer_amount            WHERE account_id=from_account;             UPDATE account_balance              SET balance=balance+tfer_amount            WHERE account_id=to_account;           COMMIT;             SET status=0;           SET message='OK';      ELSE           ROLLBACK;           SET status=-1;           SET message='Insufficient funds';      END IF;  END;  

  

Optimistic lock example:
CREATE PROCEDURE tfer_funds      (from_account INT, to_account INT, tfer_amount NUMERIC(10,2),          OUT status INT, OUT message VARCHAR(30) )    BEGIN        DECLARE from_account_balance    NUMERIC(8,2);      DECLARE from_account_balance2   NUMERIC(8,2);      DECLARE from_account_timestamp1 TIMESTAMP;      DECLARE from_account_timestamp2 TIMESTAMP;        SELECT account_timestamp,balance          INTO from_account_timestamp1,from_account_balance              FROM account_balance              WHERE account_id=from_account;        IF (from_account_balance>=tfer_amount) THEN            -- Here we perform some long running validation that          -- might take a few minutes */          CALL long_running_validation(from_account);            START TRANSACTION;            -- Make sure the account row has not been updated since          -- our initial check          SELECT account_timestamp, balance              INTO from_account_timestamp2,from_account_balance2              FROM account_balance              WHERE account_id=from_account              FOR UPDATE;            IF (from_account_timestamp1 <> from_account_timestamp2 OR              from_account_balance    <> from_account_balance2)  THEN              ROLLBACK;              SET status=-1;              SET message=CONCAT("Transaction cancelled due to concurrent update",                  " of account"  ,from_account);          ELSE              UPDATE account_balance                  SET balance=balance-tfer_amount                  WHERE account_id=from_account;                UPDATE account_balance                  SET balance=balance+tfer_amount                  WHERE account_id=to_account;                COMMIT;                SET status=0;              SET message="OK";          END IF;        ELSE          ROLLBACK;          SET status=-1;          SET message="Insufficient funds";      END IF;  END

5. Transaction Design Guide
Keep transactions short as much as possible to avoid rollback in transactions as much as possible to avoid savepoint by default, depending on the pessimistic lock for throughput demanding transactions consider optimistic lock shows that the less rows declared to open the transaction lock, the better, the shorter the lock time, the better.

  

 

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.