php mysql事务详解

本文涉及的产品
云数据库 RDS MySQL Serverless,0.5-2RCU 50GB
简介:

事务(Transaction)及其ACID属性
事务是由一组SQ语句组成的逻辑处理单元,事务具有以下4个属性,通常简称为事务的ACID属性。
原子性(Atomicity):事务是一个原子操作单元,其对数据的修改,要么全都执行,要么全都不执行。
一致性(Consistent):在事务开始和完成时,数据都必须保持一致状态。这意味着所有相关的数据规则都必须应用于事务的修改,以保持数据的完整性;事务结束时,所有的内部数据结构(如B树索引或双向链表)也都必须是正确的。
隔离性(Isoation):数据库系统提供一定的隔离机制,保证事务在不受外部并发操作影响的“独立”环境执行。这意味着事务处理过程中的中间状态对外部是不可见的,反之亦然。
持久性(Durabe):事务完成之后,它对于数据的修改是永久性的,即使出现系统故障也能够保持。

事物一般和异常处理结合

Java代码   收藏代码
  1. <?php  
  2. $lnk = mysql_connect("localhost""root""");  
  3. mysql_select_db("test");  
  4.   
  5. mysql_query("BEGIN");  
  6. try {  
  7.     mysql_query("INSERT INTO test VALUES(1, 'yangjun')");  
  8.     mysql_query("INSERT INTO test VALUES(1, 'yangjun')");  
  9.     mysql_query("INSERT INTO test VALUES(2, '杨俊')");  
  10.       
  11.     mysql_query("COMMIT"); //全部成功,提交执行结果  
  12. }catch (Exception $e){  
  13.     //$e->getMessage();  
  14.     mysql_query("ROLLBACK"); //有任何错误发生,回滚并取消执行结果  
  15. }  

在这里要注意,

MyISAM:不支持事务 ,用于只读程序提高性能
InnoDB:支持ACID事务、行级锁、并发
Berkeley DB:支持事务

还有一点要注意:MySQL默认的行为是在每条SQL语句执行后执行一个COMMIT语句,从而有效的将每条语句独立为一个事务。
但往往,我们需要在使用事务的时候,是需要执行多条sql语句的。这就需要我们手动设置MySQL的autocommit属性为0,默认为1。
同时,使用START TRANSACTION语句显式的打开一个事务 。如上面的示例。
如果不这样做,会有什么结果呢?

我们将上面第二段代码中 //mysql_query(‘SET autocommit=0′); 和 // mysql_query($sql3); 注释去掉,然后执行。
此时,mysql_query($sql3) 执行就不会insert到数据库中。

Java代码   收藏代码
  1. //对于不支持事务的MyISAM引擎数据库可以使用表锁定的方法:  
  2. $sql_1=" LOCK TABLES test WRITE ";  
  3. mysql_query($sql_1);  
  4.   
  5. $sql_2=" INSERT INTO test VALUES('".$a."','".$b."') ";  
  6. if(mysql_query($sql_2)){  
  7.   echo 'successful!';  
  8. }else{  
  9.   echo 'Unsuccessful!';  
  10.  }  
  11. $sql_3=" UNLOCK TABLES ";  
  12. mysql_query($sql_3);   

如果我们将 // mysql_query(‘SET autocommit=1′); 本句注释去掉,那么mysql_query($sql3); 就会执行成功。

通常COMMIT或ROLLBACK语句执行时才完成一个事务,但是有些DDL语句等会隐式触发COMMIT。

比如下列语句

Java代码   收藏代码
  1. ALTER FUNCTION  
  2. ALTER PROCEDURE  
  3. ALTER TABLE  
  4. BEGIN  
  5. CREATE DATABASE  
  6. CREATE FUNCTION  
  7. CREATE INDEX  
  8. CREATE PROCEDURE  
  9. CREATE TABLE  
  10. DROP DATABASE  
  11. DROP FUNCTION  
  12. DROP INDEX  
  13. DROP PROCEDURE  
  14. DROP TABLE  
  15. UNLOCK TABLES  
  16. LOAD MASTER DATA  
  17. LOCK TABLES  
  18. RENAME TABLE  
  19. TRUNCATE TABLE  
  20. SET AUTOCOMMIT=1  
  21. START TRANSACTION  

 我们再来举个例子看下。

Java代码   收藏代码
  1. $sql1 = 'create table ScoreDetail_new(id int)';  
  2. $sql2 = 'rename table ScoreDetail to ScoreDetail_bak';  
  3. $sql3  = 'rename table ScoreDetail_new to ScoreDetail';  
  4.   
  5. $mysqli = new mysqli('localhost','root','','DB_Lib2Test');  
  6. $mysqli->autocommit(false);//开始事物  
  7. $mysqli->query($sql1);  
  8. $mysqli->query($sql2);  
  9. $mysqli->query($sql3);  
  10. if(!$mysqli->errno){  
  11.   $mysqli->commit();  
  12.   echo 'ok';  
  13. }else{  
  14.  echo 'err';  
  15.   $mysqli->rollback();  
  16. }  

在上面的示例中,假如$sql2执行出错了,$sql1照样会执行的。为什么呢?
因为rename在执行的时候,mysql默认会先执行commit,再执行rename。

Mysql不支持嵌套事务

Java代码   收藏代码
  1. set autocommit=0;   
  2. start TRANSACTION ;   
  3. insert into person (firstName,lastName) VALUES ('tr1','tr2');   
  4.   
  5.     START transaction ;   
  6.     --这个时候前一个事务已经被commit了. insert了一次.   
  7.     insert into person (firstName,lastName) VALUES ('tr1','tr2');   
  8.     commit;   
  9.     --又insert了一遍   
  10. ROLLBACK;   

START TRANSACTION:开始事务,如果已经有一个事务在运行,则会触发一个隐藏的COMMIT . 

用savepoint事物嵌套

Java代码   收藏代码
  1. mysql> update books set free =1new=1;  
  2. Query OK, 0 rows affected (0.06 sec)  
  3. Rows matched: 79  Changed: 0  Warnings: 0  
  4.   
  5. mysql> commit;  
  6. Query OK, 0 rows affected (0.00 sec)  
  7.   
  8. mysql> SET AUTOCOMMIT=1;  
  9. Query OK, 0 rows affected (0.00 sec)  
  10.   
  11. mysql> begin;   
  12. Query OK, 0 rows affected (0.00 sec)  
  13.   
  14. mysql> select free, new from books limit 1;  
  15. +------+-----+  
  16. | free | new |  
  17. +------+-----+  
  18. |    1 |   1 |  
  19. +------+-----+  
  20. 1 row in set (0.00 sec)  
  21.   
  22. mysql> update books set free = 0;  
  23. Query OK, 79 rows affected (0.01 sec)  
  24. Rows matched: 79  Changed: 79  Warnings: 0  
  25.   
  26. mysql> select free, new from books limit 1;  
  27. +------+-----+  
  28. | free | new |  
  29. +------+-----+  
  30. |    0 |   1 |  
  31. +------+-----+  
  32. 1 row in set (0.00 sec)  
  33.   
  34. mysql> SAVEPOINT book1;  
  35. Query OK, 0 rows affected (0.00 sec)  
  36.   
  37. mysql> update books set new = 0;  
  38. Query OK, 79 rows affected (0.00 sec)  
  39. Rows matched: 79  Changed: 79  Warnings: 0  
  40.   
  41. mysql> select free, new from books limit 1;  
  42. +------+-----+  
  43. | free | new |  
  44. +------+-----+  
  45. |    0 |   0 |  
  46. +------+-----+  
  47. 1 row in set (0.00 sec)  
  48.   
  49. mysql> rollback to book1;  
  50. Query OK, 0 rows affected (0.00 sec)  
  51.   
  52. mysql> select free, new from books limit 1;  
  53. +------+-----+  
  54. | free | new |  
  55. +------+-----+  
  56. |    0 |   1 |  
  57. +------+-----+  
  58. 1 row in set (0.00 sec)  
  59.   
  60. mysql> rollback;  
  61. Query OK, 0 rows affected (0.05 sec)  
  62.   
  63. mysql> select free, new from books limit 1;  
  64. +------+-----+  
  65. | free | new |  
  66. +------+-----+  
  67. |    1 |   1 |  
  68. +------+-----+  
  69. 1 row in set (0.00 sec)  

  

创建可抛出一个异常的函数

Java代码   收藏代码
  1. <?php   
  2. //创建可抛出一个异常的函数  
  3. function checkNum($number){  
  4.     if($number>1){  
  5.         throw new SqlException("Value must be 1 or below");  
  6.     }  
  7.     return true;  
  8. }  
  9. //在 "try" 代码块中触发异常  
  10. try{  
  11.     checkNum(2);  
  12.     //如果异常被抛出,那么下面一行代码将不会被输出  
  13.     echo 'If you see this, the number is 1 or below';  
  14. }catch(Exception $e){  
  15.     //捕获异常  
  16.     echo 'Message: ' .$e->getMessage();  
  17. }catch(SqlException $e){  
  18.     //捕获异常  
  19.     echo 'Message: ' .$e->getMessage();  
  20. }  
  21. class SqlException extends Exception{}  
  22. ?>   
相关实践学习
基于CentOS快速搭建LAMP环境
本教程介绍如何搭建LAMP环境,其中LAMP分别代表Linux、Apache、MySQL和PHP。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助 &nbsp; &nbsp; 相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
相关文章
|
22天前
|
SQL 关系型数据库 MySQL
轻松入门MySQL:保障数据完整性,MySQL事务在进销存管理系统中的应用(12)
轻松入门MySQL:保障数据完整性,MySQL事务在进销存管理系统中的应用(12)
|
1月前
|
关系型数据库 MySQL 数据库
MySQL事务(简单明了)
MySQL事务(简单明了)
|
1月前
|
SQL 关系型数据库 MySQL
MySQL索引与事务
MySQL索引与事务
103 0
|
1月前
|
关系型数据库 MySQL 数据库
深入探讨MySQL并发事务的问题及解决方案
深入探讨MySQL并发事务的问题及解决方案
74 0
|
1月前
|
SQL 关系型数据库 MySQL
【MySQL 数据库】4、MySQL 事务学习
【MySQL 数据库】4、MySQL 事务学习
44 0
|
2月前
|
SQL 关系型数据库 MySQL
Mysql事务隔离级别和锁特性
Mysql事务隔离级别和锁特性
|
1天前
|
存储 SQL 关系型数据库
MySQL 事务
MySQL 事务
|
10天前
|
PHP
web简易开发——通过php与HTML+css+mysql实现用户的登录,注册
web简易开发——通过php与HTML+css+mysql实现用户的登录,注册
|
15天前
|
存储 SQL 关系型数据库
【MySQL实战笔记】03.事务隔离:为什么你改了我还看不见?-02
【4月更文挑战第7天】数据库通过视图实现事务隔离,不同隔离级别如读未提交、读已提交、可重复读和串行化采用不同策略。以可重复读为例,MySQL使用多版本并发控制(MVCC),每个事务有其独立的视图。回滚日志在无更早视图时被删除。长事务可能导致大量存储占用,应避免。事务启动可显式用`begin`或设置`autocommit=0`,但后者可能意外开启长事务。建议使用`autocommit=1`并显式管理事务,若需减少交互,可使用`commit work and chain`。
30 5
|
27天前
|
关系型数据库 MySQL 测试技术
面试-MySQL的四种事务隔离级别
面试-MySQL的四种事务隔离级别
18 0