MySQL InnoDB - 对交易感到困惑

时间:2011-01-27 16:23:02

标签: php mysql transactions innodb

我使用MySQL已经很多年了,但是没有很多使用InnoDB引擎的经验。

我现在正在对它进行一些测试,因为我将要使用它&从我所读到的内容来看,如果THAT交易中的任何查询存在任何问题,则不应该允许任何“通过”。

我的问题是,为什么,在下面的代码....当第三个查询显然有问题时,它仍然将前两个查询输入数据库吗?

$query = "BEGIN";
mysql_query($query);

$query = "INSERT INTO list_columns(lid,column_name) VALUES(8,'test')";
mysql_query($query);

$query = "INSERT INTO list_columns(lid,column_name) VALUES(8,'test')";
mysql_query($query);

$query = "INSERT INT list_columns(lid,column_name) VALUES(8,'test')";
mysql_query($query);

$query = "COMMIT";
mysql_query($query);

修改我了解使用ROLLBACK&所有.....但我认为事务的整个目的是这样的,如果事务中的任何查询都有任何问题,那么它们中的任何一个都将被执行......或者只有多个插入的情况例如,在一个查询中....如果其中一个插入存在问题,那么将不插入任何一个?

4 个答案:

答案 0 :(得分:10)

如果问题类似于“此插件违反了唯一键”,则会进行提交。您必须检查自己查询是否返回错误,如果是,则ROLLBACK

如果问题是例如意外关闭服务器,则不会发生查询1和2.

当然,由于你的3个查询是相同的,这是一个愚蠢的例子。 Atleast更改lid以查看。你为什么不做快速测试?

编辑:您编辑了有关交易目的的问题。

事务的目的确实是以使数据库保持一致状态(在ACID上阅读),但由程序员决定什么是一致的。查看prodigitalson's answer以查看可能的错误捕获方式的示例,为您执行此操作。但是当您处于事务中时,其他进程将无法看到您的事务正在进行的更改 - 因此是原子的和隔离的。

CREATE TABLE `testkeys` (
  `lid` INT,
  `column_name` VARCHAR(50),
  UNIQUE KEY `testuniq` (`lid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;

BEGIN;
INSERT INTO testkeys(lid,column_name) VALUES(1,'test 1');
INSERT INTO testkeys(lid,column_name) VALUES(2,'test 2');
INSERT INTO testkeys(lid,column_name) VALUES(3,'test 3');
INSERT INTO testkeys(lid,column_name) VALUES(2,'test 2b');
COMMIT;

答案 1 :(得分:7)

添加Konerak所说的内容......这是一个简化的流程,例如PDO代替mysql

$pdo = new PDO($mysqldsn, $user, $pass);
$pdo->beginTransaction();

try {

  $pdo->query("INSERT INTO list_columns(lid,column_name) VALUES(8,'test')");
  $pdo->query("INSERT INTO list_columns(lid,column_name) VALUES(8,'test')");
  $pdo->query("INSERT INT list_columns(lid,column_name) VALUES(8,'test')");
  $pdo->commit();

} catch (PDOException $e) {

  $pdo->rollBack();
  throw $e;
}

答案 2 :(得分:1)

您需要手动检查它,如果有任何错误,您需要自己回滚它。

答案 3 :(得分:0)

当您通过php执行sql查询时,它不会像单个mysql命令那样工作。 为了使上述事务正常进行,您需要在try catch块中包装代码,并设置mysql_autocommit为关闭状态,运行insert query并使用mysql_commit提交成功的工作,或者在catch块中使用mysql_rollback,以防出现任何错误。

$con=mysqli_connect("localhost","my_user","my_password","my_db");
try{
  mysqli_autocommit($con,FALSE);

  $query = "INSERT INTO list_columns(lid,column_name) VALUES(8,'test')";
  mysql_query($query);

  $query = "INSERT INTO list_columns(lid,column_name) VALUES(8,'test')";
  mysql_query($query);

  $query = "INSERT INT list_columns(lid,column_name) VALUES(8,'test')";
  mysql_query($query);

  mysql_commit($con);

}catch{

  mysql_rollback($con);

}