当我正在使用的CodeIgniter应用程序尝试特定的UPDATE操作时,我遇到了一个非常奇怪的数据库错误。
活动记录调用是:
$this->db->update('eval_events',
array('eval_event_totalscore'=>$result['average_score'],
'eval_event_average_totalscore=>$result['average_score']),
array('eval_event_id'=>$eval_event_id));
报告的错误为:
Error Number: 1054
Unknown column 'id' in 'where clause'
UPDATE `eval_events` SET `eval_event_totalscore` = '40.0000', `eval_event_average_totalscore`
= '40.0000' WHERE `id` = '581' AND `id` = '581' AND `id` = '581' AND `id` = '581' AND `id` =
'581' AND `id` = '581' AND `id` = '581' AND `id` = '581' AND `id` = '581' AND `id` = '581' AND
`id` = '581' AND `id` = '581' AND `id` = '581' AND `id` = '581' AND `id` = '581' AND `id` = '581'
AND `eval_event_id` = '565'
嗯?那些涉及"本我"的额外连词到底是从哪里来的?
很明显,我没有通过它们,我对CI_active_record.php
的阅读也没有给我任何线索。
另外三条可能相关的信息:
- 据我所知,这种失败只发生在我的开发机器上。查询在生产机器上似乎很好
- 如果我注释掉这个对
update()
的调用,下面对update()
的调用也会以完全相同的方式损坏 - 值"581"在这些更新所属的操作的整体上下文中很重要,但它是另一个表中的键(无论如何,它绑定到名为`pid`的列,而不是`id`)
它感觉就像Active Record代码缓存了"id"="581",此时有什么东西导致它将缓存的内容写入我的UPDATE语句。
我承认,我不明白Active Record的start_cache()
/stop_cache()
/flush_cache()
方法到底有什么用——但这并不重要,因为grep -r
告诉我,在应用程序的代码库中,任何地方都没有对start_cache()
的调用。
只是咧嘴一笑,我试着在update()
呼叫失败之前立即呼叫$this->db->flush_cache()
,但没有改变任何事情。
我不知道下一步该去哪里想办法弄清楚。
有什么想法吗?任何人
好:echo
、var_export()
和debug_print_backtrace()
前往救援。
事实证明,在进行失败的update()
调用的函数之前,有一个函数总共被调用了16次。16恰好是错误UPDATE语句中额外的"id"="581"连词的数量。
在前面的函数中有以下代码(我没有写这个垃圾的任何,BTW):
$this->db->where('id',$pid); // <=== WTF???
$sql = "SELECT id FROM project_score WHERE pid=$pid AND uid=$uid AND scoretype=1";
$result = $this->db->query($sql)->row_array();
这张照片怎么了?
好吧,除了使用Active Record这一可疑的选择之外,*Active Record query()
方法不使用之前调用where()
时存储的任何内容。
因此,由16个伪条件组成的队列仍然悬而未决,等待将自己附加到出现的第一个毫无戒心的update()
(或select()
,或其他什么)调用。
为什么生产系统中不发生这种情况?
好吧,在我的开发系统上,我暂时评论了一些其他(我其实并不关心),因为我的本地PHP中缺少一些配置而失败了——当时我不想重建这些配置。
显然,无论我评论了什么,都包含一个Active Record呼叫,该呼叫被强加了16个条件,但它们恰好对那个特定的呼叫是良性的。
Sheesh!
*那么,究竟谁的想法是"主动记录"的闹剧呢?
让where()
这样的函数在全局对象上排队是个好主意吗?一个更好的设计不是让每个SQL语句都成为一个不同的对象,这样在构建一个SQL语句时犯的错误就不会破坏应用程序中完全不同的部分中的另一个吗?