
奇怪的是,刷新页面之后这段代码似乎对查询结果没有任何影响,后来经过同事提醒,才知道数据库结构变动之后要主动清除TP框架的缓存。问题虽然得到了解决,但是我仍心有余悸:TP3.2究竟对数据库查询做了什么,为什么缓存会对实时查询产生影响?
经过仔细排查,最后我们跟踪到了这里:
public function select($options=array()) {
$pk = $this->getPk();
if(is_string($options) || is_numeric($options)) {
// 根据主键查询
if(strpos($options,',')) {
$where[$pk] = array('IN',$options);
}else{
$where[$pk] = $options;
}
$options = array();
$options['where'] = $where;
}elseif (is_array($options) && (count($options) > 0) && is_array($pk)) {
// 根据复合主键查询
$count = 0;
foreach (array_keys($options) as $key) {
if (is_int($key)) $count++;
}
if ($count == count($pk)) {
$i = 0;
foreach ($pk as $field) {
$where[$field] = $options[$i];
unset($options[$i++]);
}
$options['where'] = $where;
} else {
return false;
}
} elseif(false === $options){ // 用于子查询 不查询只返回SQL
$options['fetch_sql'] = true;
}
// 分析表达式
$options = $this->_parseOptions($options);
...
在_parseOptions方法中:protected function _parseOptions($options=array()) {
if(is_array($options))
$options = array_merge($this->options,$options);
if(!isset($options['table'])){
// 自动获取表名
$options['table'] = $this->getTableName();
$fields = $this->fields;
}else{
// 指定数据表 则重新获取字段列表 但不支持类型检测
$fields = $this->getDbFields();
}
// 数据表别名
if(!empty($options['alias'])) {
$options['table'] .= ' '.$options['alias'];
}
// 记录操作的模型名称
$options['model'] = $this->name;
// 字段类型验证
if(isset($options['where']) && is_array($options['where']) && !empty($fields) && !isset($options['join'])) {
// 对数组查询条件进行字段类型检查
foreach ($options['where'] as $key=>$val){
$key = trim($key);
if(in_array($key,$fields,true)){
if(is_scalar($val)) {
$this->_parseType($options['where'],$key);
}
}elseif(!is_numeric($key) && '_' != substr($key,0,1) && false === strpos($key,'.') && false === strpos($key,'(') && false === strpos($key,'|') && false === strpos($key,'&')){
if(!empty($this->options['strict'])){
E(L('_ERROR_QUERY_EXPRESS_').':['.$key.'=>'.$val.']');
}
unset($options['where'][$key]);
}
}
}
...
在这部分程序中,我们发现,传入的一部分查询条件被过滤了( unset($options['where'][$key])),原因是我们新增的字段被存储到$options['where']的key中,但是这个key并没有存在于$fields中。接下来我们来追踪$options的来源: 
我们看到:$options数组的内容是在执行select操作时执行的。那么$fields这个变量的内容又是在哪儿初始化的呢?


从上图可知,程序在实例化数据库时,就已经初始化了$fields变量。到这里,所有的谜团都解开了。TP会将数据库的表字段信息缓存在文件中,然后当PHP程序执行到相关的数据库操作时,会直接从缓存文件中获取相关的表字段信息,然后进行验证和检查。由于我们新增了字段,却没有更新缓存,新增加的部分查询条件自然就"丢失"了。
OVER.