mysql事务实战

mysql事务主要用于处理操作量大,复杂度高的数据。比如说,在人员管理系统中,你删除一个人员,你既要删除人员的基本资料,也要删除和该人员相关的信息,如信箱,文章等。这样,这些数据库操作语句就构成一个事务。注意一下几点:

  • 在MySQL中只有使用了Innodb数据库引擎的数据库或表才支持事务。
  • 事务处理可以用来维护数据库的完整性,保证成批的sql语句要么全部执行,要么全部不执行。
  • 事务用来管理insert,update,delete语句。

 

 

mysql> SELECT * FROM ordertotals;
+-----------+-----------------+-------------+
| order_num | total_not_taxed | total_taxed |
+-----------+-----------------+-------------+
|     20005 |          149.87 |      222.00 |
|     20009 |           38.47 |       40.78 |
|     20006 |           55.00 |       58.30 |
|     20007 |         1000.00 |     1060.00 |
|     20008 |          125.00 |      132.50 |
|     20008 |          125.00 |      132.50 |
|     11111 |          100.00 |      125.00 |
|     11111 |          100.00 |      125.00 |
+-----------+-----------------+-------------+
8 rows in set (0.00 sec)

mysql> START TRANSACTION;
Query OK, 0 rows affected (0.00 sec)

mysql> DELETE FROM ordertotals WHERE order_num = 11111;
Query OK, 2 rows affected (0.00 sec)

mysql> SELECT * FROM ordertotals;
+-----------+-----------------+-------------+
| order_num | total_not_taxed | total_taxed |
+-----------+-----------------+-------------+
|     20005 |          149.87 |      222.00 |
|     20009 |           38.47 |       40.78 |
|     20006 |           55.00 |       58.30 |
|     20007 |         1000.00 |     1060.00 |
|     20008 |          125.00 |      132.50 |
|     20008 |          125.00 |      132.50 |
+-----------+-----------------+-------------+
6 rows in set (0.00 sec)

mysql> ROLLBACK;
Query OK, 0 rows affected (0.01 sec)

mysql> SELECT * FROM ordertotals;
+-----------+-----------------+-------------+
| order_num | total_not_taxed | total_taxed |
+-----------+-----------------+-------------+
|     20005 |          149.87 |      222.00 |
|     20009 |           38.47 |       40.78 |
|     20006 |           55.00 |       58.30 |
|     20007 |         1000.00 |     1060.00 |
|     20008 |          125.00 |      132.50 |
|     20008 |          125.00 |      132.50 |
|     11111 |          100.00 |      125.00 |
|     11111 |          100.00 |      125.00 |
+-----------+-----------------+-------------+
8 rows in set (0.00 sec)

mysql>
事务演示

 

mysql的事务处理主要有两种方法:

1. begin,rollback,commit来实现

begin 开始一个事务

rollback 事务回滚

commit 事务确认,事务提交

2,直接用set来改变mysql的自动提交模式

mysql默认z是自动提交的,也就是你提交一个query,它就直接执行。

set autocommit = 0 禁止自动提交模式

set autocommit = 1 开启自动提交模式

 

  mysql中只用INNODB和BDB类型的数据表才能支持事务处理(切记)!

 

来看一个例子:

先假设一下问题的背景:网上购书,某书《mysql数据库》编号为123,只剩最后一本,而这个时候两个用户几乎同时对这本书发出了购书请求,让我们来看看整个过程:

在具体分析之前,先来看看数据表的定义:

 

  对于用户甲来说,他的动作稍微比乙快一点点,其购买过程中所触发的动作大致是这样的:

1.select book_number from book where book_id = 123;

book_number 大于0,确认购买行为并更新book_number 

2.update book set book_number = book_number—1 where book_id = 123; 

  购书成功

 

表面上看甲乙的操作都成功了,他们都买到了书,但是库存只有一本,他们怎么可能都成功呢?再看看数据表里book_number的内容,已经变成“-1”了,这当然是不能允许的(实际上,声明这样的列类型应该加上unsigned的属性,以保证其不能为负,这里是为了说明问题所以没有这样设置) 

  好了,问题陈述清楚了,再来看看怎么利用事务来解决这个问题,打开MySQL手册,可以看到想用事务来保护你的SQL正确执行其实很简单,基本就是三个语句:开始,提交,回滚。

 

开始:START TRANSACTION或BEGIN语句可以开始一项新的事务

提交:COMMIT可以提交当前事务,是变更成为永久变更

回滚:ROLLBACK可以回滚当前事务,取消其变更

此外,SET AUTOCOMMIT = {0 | 1}可以禁用或启用默认的autocommit模式,用于当前连接。

 

那是不是只要用事务语句包一下我们的SQL语句就能保证正确了呢?比如下面代码: 

 

  答案是否定了,这样依然不能避免问题的发生,如果想避免这样的情况,实际应该如下:

 

  由于加入了FOR UPDATE,所以会在此条记录上加上一个行锁,如果此事务没有完全结束,那么其他的事务在使用SELECT ... FOR UPDATE请求的时候就会处于等待状态,直到上一个事务结束,它才能继续,从而避免了问题的发生,需要注意的是,如果你其他的事务使用的是不带FOR UPDATE的SELECT语句,将得不到这种保护。

posted @ 2015-05-23 20:05  南哥的天下  阅读(5212)  评论(0编辑  收藏  举报