2

我没有在我的程序中使用事务,所以我认为所有数据库操作都会立即提交。

我有一个 php 程序在表中查找值,如果找到则返回 id。如果没有找到,它会写入一个新行。后来它重复,它应该找到我刚刚插入的数据,但它不是,所以我得到一个重复的错误。

如何强制 mysql 写入数据,以便在插入后得到有效结果?我试过刷新表,但这并没有改变我的结果。

更多细节:

我认为这是一个通用的 mysql 问题,但它似乎与使用 Cakephp 的模型查询有关。

我正在使用控制器将 CSV 文件解析为多个表,因此动态绑定模型并在遇到数据时使用查询调用将数据插入表中。我在应用程序的其余部分使用 CakePHP,但是解析能力是一种一次性的功能,所以我没有花很多时间试图让它变得优雅。

Import 模型没有关联的表,所以我手动绑定到 Tracking 模型。

将代码解释为相关查询:

    $this->Import->bindModel(array('hasOne' => array('Tracking')));

    $insert =<<<DONE
INSERT INTO tracking (id, created, employee_id, client_id, borrower_name, loan_number,
                  loan_amount, activity_id, program_id, rate_id, lock_period,
                  lo_price, investor_price,  committed_price, purchase_advice_price,
                  lock_type, investor_id, time_taken, notes,audited,audit_notes,
                  import_notes, import_error, uniqueness)
                  VALUES (NULL, '%s', %d,  %d,  '%s', '%s',
                          %.2f, %d, %d,  %d, %d,
                          %.5f, %.5f, %.5f, %.5f,
                          %d, %d, %d, '%s', %d, '%s',
                          '%s', %d, %d)
DONE;
while ($row = fgetscsv($fh))
    # Lots of processing deleted

    if (! $this->_exists($row))
    {
       $sql = vsprint($insert, $row);
       $this->Import->Tracking->query($sql); # This is where I'll get a duplicate error
    }
} # end of function

# I've created a unique index on columns that should be unique and I do the query on    
# them here.
private _exists($mydata)
{
       $find = "SELECT id FROM tracking WHERE created = '%s' AND employee_id = %d" AND
            activity_id = $d AND ...";
       $sql = sprintf($find, $mydata[0], $mydata[1]);
       return $this->Import->Tracking->query($sql);
}

所以,问题似乎是 Cakephp 以及它对模型查询所做的任何事情。

我可能可以将这段代码从 Cake 中提取出来并使用一个独立的 php 程序,但由于我已经在使用 Cakephp,所以我想我会将导入模型放入其中。

附加评论:选择是正确的,但我没有逐字转录,因为它很长,我用省略号来表示。它确实有效,因为我可以复制/粘贴到 mysql 会话中并选择数据。第二次运行它,它会找到数据。

对于其他人来说,Cakephp 可能会将整个事情包装成一个大事务,直到您退出控制器才会提交?这不能解释为什么它第二次运行它会找到那些行吗?

我想我要么需要弄清楚如何让 Cakephp 提交这些插入,或者我不应该为此使用 Model->query 并以另一种方式来做,或者在我的项目的这一部分中不使用 Cakephp。

====

谢谢!

4

5 回答 5

1

在 CakePHP 2.5.5 上,仅供参考(即使是我自己,如果我忘记了解决方案并在将来找到自己的答案......你好!),好吧,这个问题是由于查询缓存造成的。修复:

$this->Import->Tracking->query($sql, false);

添加false参数将关闭查询缓存。只需阅读有关方法http://api.cakephp.org/2.5/source-class-Model.html#3363-3366的评论

于 2015-05-20T01:41:37.387 回答
0

您可能正在寻找 LAST_INSERT_ID()

http://dev.mysql.com/doc/refman/5.0/en/information-functions.html#function_last-insert-id

于 2013-07-26T21:56:41.293 回答
0

您的 $find 不是有效字符串:

   $find = "SELECT id FROM tracking WHERE created = "%s" AND employee_id = %d" AND activity_id = $d AND ...";
   //                                               ^ this is terminating the string

您需要将其用单引号括起来以使其成为文字字符串。像这样:

   $find = 'SELECT id FROM tracking WHERE created = "%s" AND employee_id = %d" AND activity_id = $d AND ...';

或者转义字符串中的引号(不知道为什么在这种情况下你会这样做):

   $find = "SELECT id FROM tracking WHERE created = \"%s\" AND employee_id = \"%d\" AND activity_id = $d AND ...";
于 2013-07-26T23:01:31.533 回答
0

如果您对表有UNIQUE约束(并且从代码中的注释中我看到您这样做),您可以使用INSERT IGNORE

INSERT IGNORE INTO tracking (...)
VALUES (...)

这说明了在做SELECT之前的需要INSERT


要考虑的另一个选项是将处理 CSV 文件的方式更改为以下内容:

  1. 创建一个没有约束的临时表,其中包含VARCHAR用于导入数据的所有必要列(最好是 type )和一个 auto_incremented id 字段
  2. 用于LOAD DATA INFILE以最有效的方式将 CSV 文件加载到临时表中
  3. 现在您可以使用所有 SQL 工具轻松清理、规范化、转换、对照参考表和事实表验证临时表中的数据
  4. 将临时表中的数据插入到事实表中
  5. 截断你的临时表

您甚至可以将 p3-5 包装到一个存储过程中,这可以进一步简化您的客户端代码。

于 2013-07-27T07:02:17.477 回答
0

我认为我遇到的是 CakePHP 对 Query 方法所做的事情。我重新编码了控制器,以便它可以即时创建与模型的关联,并使用内置的模型保存方法。

这是一个更优雅的解决方案,即使它需要更多的编码。它还使我不必深入研究 CakePHP 的核心并弄清楚查询方法在做什么。

感谢大家的想法!

于 2013-08-20T17:19:23.777 回答