Mysql Programming CS 155P笔记(六) Transactions

Transactions

A transaction is a set of statements all of which need to complete or none of which should complete. 

In many complex cases, it's impossible to do everything you need in a single SQL statement.

Lets look at a couple examples:

SHOPPING CART Checkout transaction:
In our shopping cart, when a customer wants to checkout and buy all the items in their cart, a series of things need to happen effectively all at the same time.  For simplicity sake, lets say that we aren't allowed to sell more inventory than we have (no backorders or online download [unlimited inventory]):

We've collected all the billing and shipping and payment info.  We now need to do the following:

  1. store the payment confirmation
  2. reduce the inventory of each item
  3. add the purchase to the users transaction history
  4. identify customers to the vendors for warranty information or customer notifications
  5. clear the users shopping cart

This is likely done via a series of SQL statements.. at least one per task, but some tasks may have multiple queries.  In any case, if any of these steps doesn't work (we ran out of inventory, for example), we don't want any of these queries to actually change database info (we certainly shouldn't clear the cart--although we may want to remove the out of inventory item or mark it as unavailable in the users cart), we don't want to add this to the transaction history, we shouldn't reduce inventory of other items since we aren't completing this transaction, and we should reverse the payment transaction (ideally this is done via a hold which is lifted rather than a purchase that is reversed, but that's out of scope for this class).

Without transactions, out software would have to keep track of all the queries executed and when it ran into a problem, we'd have to run queries to undo all the work we just did.

In the transactions world, we can simply roll back the transaction and all pending DB changes would be undone.    Similarly, if we're happy and everything is fine, we can commit the changes and all tables will be updated effectively simultaneously.

Transaction commit and rollback can be included in procedures/functions as well.

Here's an example:

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

START TRANSACTION, COMMIT和ROLLBACK语法

START TRANSACTION | BEGIN [WORK]
COMMIT [WORK] [AND [NO] CHAIN] [[NO] RELEASE]
ROLLBACK [WORK] [AND [NO] CHAIN] [[NO] RELEASE]
SET AUTOCOMMIT = {0 | 1}

在默认情况下MySQL会采用autocommite模式运行,这意味着更新或修改表的语句后,MySQL就会立即存储到硬盘内,如果你使用InnoDB或NDB引擎,你可以关闭这个自动保存的选项,SET AUTOCOMMIT=0; 另外一种方法就是声明使用 start transaction; 这个statement。

In this example, for whatever reason, the insert into table c should fail (perhaps it doesn't have a date column).   our continue handler sets the variable _rollback to true, so then we rollback the transaction.  Otherwise, we commit the transaction.

Since the first 2 queries were successful, rollback will do the work for us of removing the rows that were added.

In the "resources" for this weeks section is a 7 minute youtube clip on MySQL Transactions, please watch it.

There are also 2 tutorials from different sources.  I suggest you review at least one of them.

Why Transactions?

The fundamental desire for a database is ACID compliance:

ACID

  • Atomicity − This ensures that all operations within the work unit are completed successfully; otherwise, the transaction is aborted at the point of failure and previous operations are rolled back to their former state.

  • Consistency − This ensures that the database properly changes states upon a successfully committed transaction.

  • Isolation − This enables transactions to operate independently on and transparent to each other.

  • Durability − This ensures that the result or effect of a committed transaction persists in case of a system failure.

A single query will lock the database so that all it's additions/changes/deletions are completed before another query can update or read data from the same table.

一般来说,事务是必须满足4个条件(ACID)::原子性(Atomicity,或称不可分割性)、一致性(Consistency)、隔离性(Isolation,又称独立性)、持久性(Durability)。

  • 原子性:一个事务(transaction)中的所有操作,要么全部完成,要么全部不完成,不会结束在中间某个环节。事务在执行过程中发生错误,会被回滚(Rollback)到事务开始前的状态,就像这个事务从来没有执行过一样。

  • 一致性:在事务开始之前和事务结束以后,数据库的完整性没有被破坏。这表示写入的资料必须完全符合所有的预设规则,这包含资料的精确度、串联性以及后续数据库可以自发性地完成预定的工作。就拿网上购物来说吧,你只有即让商品出库,又让商品进入顾客得购物篮才能构成事务

  • 隔离性:数据库允许多个并发事务同时对其数据进行读写和修改的能力,隔离性可以防止多个事务并发执行时由于交叉执行而导致数据的不一致。事务隔离分为不同级别,包括读未提交(Read uncommitted)、读提交(read committed)、可重复读(repeatable read)和串行化(Serializable)。

  • 持久性:事务处理结束后,对数据的修改就是永久的,即便系统故障也不会丢失。一个成功执行得事务对数据库得作用是持久得,即使数据库应故障出错,也应该能够恢复

It would be bad if one query was changing 1 million rows and another query were reading those rows at the same time.  The one reading may not get the correct state of all the rows if some change before it read their data and after it's read other rows data.  With transactions it's important that changes to all tables relative to the are executed simultaneously so they won't affect other queries or transactions.

For this reason, it's important to be aware of the impact your transactions will have on the DB when they're executed.   If you have a transaction that will take a very long time to commit, many tables may be locked for a long time preventing other transactions or queries from executing. 

You may have noticed certain sites you visit might operate more slowly late at night than they do during the day.  In many cases, like your bank, for example, they run large batch process which can sometimes consist of bulky transactions and you're query to view your account statement may have to wait until they finish processing the transactions relative to your account from the past day.

Gotcha's

When using transactions it's very important to be aware of things that might perform actions when you didn't intend them.

Some statements cannot be rolled back, while others force an implicit commit. 

Any transaction with statements which create, drop, or alter a DB cannot be rolled back.   These really shouldn't be part of transactions but there are some use cases where this is done. (需要注意create, drop, alter这些statments是唔可以rolled back的)

Since this statement can't be rolled back, any statements issued up to that point also can't be rolled back.  Those same statements force an implicit commit to all the transactions that happened before the statement.  

Similarly, drop, alter and create functions statements force an implicit commit and cannot be rolled back.

Be sure to understand the statements which cause an implicit commit.  Read the MySQL Documentation on implicit commit (Links to an external site.)Links to an external site..

A good rule of thumb is, if the query relates to "data" then it can be rolled back, if it relates to structures or code or metadata then it likely can't be rolled back and would also force an implicit commit.

事务测试:

mysql> use RUNOOB;
Database changed
mysql> CREATE TABLE runoob_transaction_test( id int(5)) engine=innodb;  # 创建数据表
Query OK, 0 rows affected (0.04 sec)
 
mysql> select * from runoob_transaction_test;
Empty set (0.01 sec)
 
mysql> begin;  # 开始事务
Query OK, 0 rows affected (0.00 sec)
 
mysql> insert into runoob_transaction_test value(5);
Query OK, 1 rows affected (0.01 sec)
 
mysql> insert into runoob_transaction_test value(6);
Query OK, 1 rows affected (0.00 sec)
 
mysql> commit; # 提交事务
Query OK, 0 rows affected (0.01 sec)
 
mysql>  select * from runoob_transaction_test;
+------+
| id   |
+------+
| 5    |
| 6    |
+------+
2 rows in set (0.01 sec)
 
mysql> begin;    # 开始事务
Query OK, 0 rows affected (0.00 sec)
 
mysql>  insert into runoob_transaction_test values(7);
Query OK, 1 rows affected (0.00 sec)
 
mysql> rollback;   # 回滚
Query OK, 0 rows affected (0.00 sec)
 
mysql>   select * from runoob_transaction_test;   # 因为回滚所以数据没有插入
+------+
| id   |
+------+
| 5    |
| 6    |
+------+
2 rows in set (0.01 sec)
 
mysql>

CREATE TABLE tbl_new AS SELECT * FROM tbl_old;

https://blog.csdn.net/u010412719/article/details/51147292

原文地址:https://www.cnblogs.com/ecwork/p/8939304.html