mysql事务回滚使用与常见问题介绍

SEO研究中心 SEO研究中心提供免费SEO公开课

MYSQL中只有INNODB和BDB类型的数据表才能支持事务处理,其他的类型是不支持的! ***:一般MYSQL数据库默认的引擎是MyISAM,这种引擎不支持事务,如果要让MYSQL支持事务,可以自己手动修改.

方法如下:

1.修改c:appservmysqlmy.ini文件,找到skip-InnoDB,在前面加上#,后保存文件。

2.在运行中输入:services.msc,重启mysql服务。

3.到phpmyadmin中,mysql->show engines;(或执行mysql->show variables like 'have_%'; ),查看InnoDB为YES,即表示数据库支持InnoDB了,也就说明支持事务transaction了.

4.在创建表时,就可以为Storage Engine选择InnoDB引擎了,如果是以前创建的表,可以使用如下代码:

  1. mysql->altertabletable_nametype=InnoDB;
  2. --或
  3. mysql->altertabletable_nameengine=InnoDB;

来改变数据表的引擎以支持事务.

事务回滚在事务中,每个正确的原子操作都会被顺序执行,直到遇到错误的原子操作,此时事务会将之前的操作进行回滚,回滚的意思是如果之前是插入操作,那么会执行删除插入的记录,如果之前是update操作,也会执行update操作将之前的记录还原,因此,正确的原子操作是真正被执行过的.

MYSQL的事务处理主要有两种方法.

1、用begin,rollback,commit来实现

begin 开始一个事务

rollback 事务回滚

commit 事务确认

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

MYSQL默认是自动提交的,也就是你提交一个QUERY,它就直接执行,我们可以通过:

set autocommit=0 禁止自动提交

set autocommit=1 开启自动提交

来实现事务的处理,当你用 set autocommit=0 的时候,你以后所有的SQL都将做为事务处理,直到你用commit确认或rollback结束.

注意当你结束这个事务的同时也开启了个新的事务,按第一种方法只将当前的作为一个事务!

PHP实现MySQL事务回滚,创建一个测试的数据库,代码如下:

  1. mysql>CREATEDATABASE`shop_test`DEFAULTCHARSET=utf8COLLATE=utf8_general_ci;
  2. QueryOK,1rowaffected(0.00sec)
  3. mysql>useshop_test;
  4. Databasechanged
  5. mysql>CREATETABLEIFNOTEXISTS`user_account`(
  6. ->`user`varchar(20)NOTNULL,
  7. ->`money`INT(10)NOTNULL,
  8. ->PRIMARYKEY(`user`)
  9. ->)ENGINE=InnoDBDEFAULTCHARSET=utf8COLLATE=utf8_general_ci;
  10. QueryOK,0rowsaffected(0.51sec)
  11. mysql>CREATETABLEIFNOTEXISTS`user_order`(
  12. ->`id`INT(10)NOTNULL,
  13. ->`user`VARCHAR(20)NOTNULL,
  14. ->`price`INT(10)NOTNULL,
  15. ->`count`INT(10)NOTNULL,
  16. ->PRIMARYKEY(`id`)
  17. ->)ENGINE=InnoDBDEFAULTCHARSET=utf8COLLATE=utf8_general_ciAUTO_INCREMENT=1;
  18. QueryOK,0rowsaffected(0.33sec)
  19. mysql>INSERTINTO`user_account`VALUES('luchanghong','100');
  20. QueryOK,1rowaffected(0.00sec)

PHP测试代码:

  1. $conn=mysql_connect('127.0.0.1','root','root');
  2. mysql_select_db('shop_test');
  3. mysql_query('SETNAMESUTF8');
  4. #starttransaction
  5. mysql_query("STARTTRANSACTION");
  6. $sql="INSERTINTO`user_order`VALUES('1','luchanghong','10','2')";
  7. mysql_query($sql);
  8. $sql_2="UPDATE`user_account`SET`money`=`money`-10*2WHERE`user`='luchanghong'";
  9. mysql_query($sql_2);
  10. //phpfensi.com
  11. if(mysql_errno()){
  12. echo"error";
  13. mysql_query("ROLLBACK");
  14. }else{
  15. echo"OK";
  16. mysql_query("COMMIT");
  17. }

执行一次后查看数据库,代码如下:

  1. mysql>SELECT*FROM`user_account`;
  2. +-------------+-------+
  3. |user|money|
  4. +-------------+-------+
  5. |luchanghong|80|
  6. +-------------+-------+
  7. 1rowinset(0.00sec)
  8. mysql>SELECT*FROM`user_order`;
  9. +----+-------------+-------+-------+
  10. |id|user|price|count|
  11. +----+-------------+-------+-------+
  12. |1|luchanghong|10|2|
  13. +----+-------------+-------+-------+
  14. 1rowinset(0.00sec)

那么,我添加一个条件,就是每次更新完 user_account 表后检查用户的 money 是否为负值,如果为负值那么就要撤销之前的操作,执行事务回滚,代码如下:

  1. $conn=mysql_connect('127.0.0.1','root','root');
  2. mysql_select_db('shop_test');
  3. mysql_query('SETNAMESUTF8');
  4. //starttransaction
  5. mysql_query("STARTTRANSACTION");
  6. $sql="INSERTINTO`user_order`(`user`,`price`,`count`)VALUES('luchanghong','10','2')";
  7. mysql_query($sql);
  8. $sql_2="UPDATE`user_account`SET`money`=`money`-10*2WHERE`user`='luchanghong'";
  9. mysql_query($sql_2);
  10. if(mysql_errno()){
  11. echo"errorn";
  12. mysql_query("ROLLBACK");
  13. }else{
  14. $money=check_remain_money('luchanghong');
  15. echo$money."";
  16. if($money<0){
  17. echo"Noenoughmoneyn";
  18. mysql_query("ROLLBACK");
  19. }else{
  20. echo"OKn";
  21. mysql_query("COMMIT");
  22. }
  23. }
  24. functioncheck_remain_money($user){
  25. $sql="SELECT`money`FROM`user_account`WHERE`user`='{$user}'";
  26. $result=mysql_fetch_assoc(mysql_query($sql));
  27. return!emptyempty($result)?$result['money']:0;
  28. }

接着,在shell下多次执行这php文件,WIN下就手动执行几次吧,代码如下:

  1. lch@LCH:~/Desktop$forxin`seq6`;dophptransaction.php;done
  2. 60OK
  3. 40OK
  4. 20OK
  5. 0OK
  6. -20Noenoughmoney
  7. -20Noenoughmoney

再看数据库数据,代码如下:

  1. mysql>SELECT*FROM`user_account`;
  2. +-------------+-------+
  3. |user|money|
  4. +-------------+-------+
  5. |luchanghong|0|
  6. +-------------+-------+
  7. 1rowinset(0.00sec)
  8. mysql>SELECT*FROM`user_order`;
  9. +----+-------------+-------+-------+
  10. |id|user|price|count|
  11. +----+-------------+-------+-------+
  12. |1|luchanghong|10|2|
  13. |2|luchanghong|10|2|
  14. |3|luchanghong|10|2|
  15. |4|luchanghong|10|2|
  16. |5|luchanghong|10|2|
  17. +----+-------------+-------+-------+
  18. 5rowsinset(0.00sec)

1、为什么auto_increament没有回滚?

因为innodb的auto_increament的计数器记录的当前值是保存在存内 存中的,并不是存在于磁盘上,当mysql server处于运行的时候,这个计数值只会随着insert改增长,不会随着delete而减少。而当mysql server启动时,当我们需要去查询auto_increment计数值时,mysql便会自动执行:SELECT MAX(id) FROM 表名 FOR UPDATE;语句来获得当前auto_increment列的最大值,然后将这个值放到auto_increment计数器中。所以就算 Rollback MySQL的auto_increament计数器也不会作负运算。

2、MySQL的事务对表操作的时候是否是物理操作?

MySQL的事务是有redo和undo的,redo操作的所有信息都是记录到 redo_log中,也就是说当一个事务做commit操作时,需要先把这个事务的操作写到redo_log中,然后再把这些操作flush到磁盘上,当 出现故障时,只需要读取redo_log,然后再重新flush到磁盘就行了.

而对于undo就比较麻烦,MySQL在处理事务时,会在数据共享 表空间里申请一个段叫做segment段,用保存undo信息,当在处理rollback,不是完完全全的物理undo,而是逻辑undo,就是说会对之 前的操作进行反操作,但是这些共享表空间是不进行回收的,这些表空间的回收需要由mysql的master thread进程来进行回收.

相关广告
  • mysql事务回滚使用与常见问题介绍 mysql事务回滚使用与常见问题介绍 mysql事务回滚使用与常见问题介绍
相关阅读

mysql事务回滚使用与常见问题介绍

2019/10/10 17:34:34 | 谷歌SEO算法 | 自学SEO