事物一般和异常处理结合
<?php $lnk = mysql_connect("localhost", "root", ""); mysql_select_db("test"); mysql_query("BEGIN"); try { mysql_query("INSERT INTO test VALUES(1, 'yangjun')"); mysql_query("INSERT INTO test VALUES(1, 'yangjun')"); mysql_query("INSERT INTO test VALUES(2, '杨俊')"); mysql_query("COMMIT"); //全部成功,提交执行结果 }catch (Exception $e){ //$e->getMessage(); mysql_query("ROLLBACK"); //有任何错误发生,回滚并取消执行结果 }
在这里要注意,
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到数据库中。
如果我们将 // mysql_query(‘SET autocommit=1′); 本句注释去掉,那么mysql_query($sql3); 就会执行成功。
通常COMMIT或ROLLBACK语句执行时才完成一个事务,但是有些DDL语句等会隐式触发COMMIT。
比如下列语句
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
我们再来举个例子看下。
$sql1 = 'create table ScoreDetail_new(id int)'; $sql2 = 'rename table ScoreDetail to ScoreDetail_bak'; $sql3 = 'rename table ScoreDetail_new to ScoreDetail'; $mysqli = new mysqli('localhost','root','','DB_Lib2Test'); $mysqli->autocommit(false);//开始事物 $mysqli->query($sql1); $mysqli->query($sql2); $mysqli->query($sql3); if(!$mysqli->errno){ $mysqli->commit(); echo 'ok'; }else{ echo 'err'; $mysqli->rollback(); }
在上面的示例中,假如$sql2执行出错了,$sql1照样会执行的。为什么呢?
因为rename在执行的时候,mysql默认会先执行commit,再执行rename。
Mysql不支持嵌套事务
set autocommit=0; start TRANSACTION ; insert into person (firstName,lastName) VALUES ('tr1','tr2'); START transaction ; --这个时候前一个事务已经被commit了. insert了一次. insert into person (firstName,lastName) VALUES ('tr1','tr2'); commit; --又insert了一遍 ROLLBACK;
START TRANSACTION:开始事务,如果已经有一个事务在运行,则会触发一个隐藏的COMMIT .
用savepoint事物嵌套
mysql> update books set free =1, new=1; Query OK, 0 rows affected (0.06 sec) Rows matched: 79 Changed: 0 Warnings: 0 mysql> commit; Query OK, 0 rows affected (0.00 sec) mysql> SET AUTOCOMMIT=1; Query OK, 0 rows affected (0.00 sec) mysql> begin; Query OK, 0 rows affected (0.00 sec) mysql> select free, new from books limit 1; +------+-----+ | free | new | +------+-----+ | 1 | 1 | +------+-----+ 1 row in set (0.00 sec) mysql> update books set free = 0; Query OK, 79 rows affected (0.01 sec) Rows matched: 79 Changed: 79 Warnings: 0 mysql> select free, new from books limit 1; +------+-----+ | free | new | +------+-----+ | 0 | 1 | +------+-----+ 1 row in set (0.00 sec) mysql> SAVEPOINT book1; Query OK, 0 rows affected (0.00 sec) mysql> update books set new = 0; Query OK, 79 rows affected (0.00 sec) Rows matched: 79 Changed: 79 Warnings: 0 mysql> select free, new from books limit 1; +------+-----+ | free | new | +------+-----+ | 0 | 0 | +------+-----+ 1 row in set (0.00 sec) mysql> rollback to book1; Query OK, 0 rows affected (0.00 sec) mysql> select free, new from books limit 1; +------+-----+ | free | new | +------+-----+ | 0 | 1 | +------+-----+ 1 row in set (0.00 sec) mysql> rollback; Query OK, 0 rows affected (0.05 sec) mysql> select free, new from books limit 1; +------+-----+ | free | new | +------+-----+ | 1 | 1 | +------+-----+ 1 row in set (0.00 sec)
创建可抛出一个异常的函数
<?php //创建可抛出一个异常的函数 function checkNum($number){ if($number>1){ throw new SqlException("Value must be 1 or below"); } return true; } //在 "try" 代码块中触发异常 try{ checkNum(2); //如果异常被抛出,那么下面一行代码将不会被输出 echo 'If you see this, the number is 1 or below'; }catch(Exception $e){ //捕获异常 echo 'Message: ' .$e->getMessage(); }catch(SqlException $e){ //捕获异常 echo 'Message: ' .$e->getMessage(); } class SqlException extends Exception{} ?>