同一控制器函数内执行不同数据库查询的问题
嘿,结合你给出的CodeIgniter控制器和模型代码,我来梳理下这种两次数据库查询场景里常见的技术问题和实用解决方案:
常见问题与对应解决方案
1. 优化查询性能,减少数据库交互
你现在的代码里两次调用Model方法执行数据库查询,首先要关注的是减少不必要的数据库请求:
- 如果
search_people()和get_skill()的业务逻辑允许,可以考虑把两个查询合并成一次关联查询,比如通过用户ID把search_result表和技能表关联起来,一次性获取人员信息和对应的技能,这样能减少一次数据库往返。 - 对高频且数据变化慢的查询做缓存:比如
get_skill()是根据分类名查技能,分类数据不会频繁更新的话,可以给这个方法加上缓存逻辑,避免重复查询数据库:
// 模型中的get_skill方法优化 function get_skill($category_name) { $cache_key = 'skill_list_' . md5($category_name); // 先从缓存取数据 if ($cached_data = $this->cache->get($cache_key)) { return $cached_data; } // 数据库查询逻辑 $this->db->select('skill_id, skill_name'); $this->db->from('skills'); $this->db->where('category', $category_name); $result = $this->db->get()->result_array(); // 将结果存入缓存,有效期设为1小时(可根据业务调整) $this->cache->save($cache_key, $result, 3600); return $result; }
2. 保证查询结果的一致性
如果两次查询之间有数据更新操作,可能会出现$people和$skills的数据不一致(比如刚更新了某用户的技能,search_people拿到的是旧数据,get_skill拿到的是新数据)。解决办法:
- 用数据库事务包裹两次查询:如果这两个查询是强关联的业务逻辑,需要保证它们的数据是同一时间点的,可以开启事务:
// 控制器中的index方法修改 function index() { $this->db->trans_start(); // 开启事务 $people = $this->M_results->search_people(); $skills = $this->M_results->get_skill($category_name); $this->db->trans_complete(); // 结束事务 // 检查事务是否成功 if ($this->db->trans_status() === FALSE) { log_message('error', '数据库事务执行失败'); // 这里可以添加错误提示或跳转逻辑 } }
- 注意:事务主要用于保证数据的原子性,如果你只是想让读操作获取一致的数据,也可以调整数据库的隔离级别(比如设置为
READ COMMITTED),具体根据你的数据库类型(MySQL、PostgreSQL等)来配置。
3. 提升代码的可读性与维护性
两次分开的Model调用如果业务逻辑关联紧密,建议把它们封装成一个Model方法,让控制器的逻辑更简洁:
// 模型中新增封装方法 function get_people_and_skills($category_name) { $people = $this->search_people(); $skills = $this->get_skill($category_name); // 可以在这里把技能数据和人员数据关联起来,比如给每个人员添加对应的技能列表 foreach ($people as &$person) { $person['related_skills'] = array_filter($skills, function($skill) use ($person) { return $skill['registration_id'] == $person['registration']; }); } return $people; } // 控制器中只需调用一次即可 function index() { $people_with_skills = $this->M_results->get_people_and_skills($category_name); // 后续逻辑使用$people_with_skills即可 }
这样业务逻辑都集中在Model层,后续修改或扩展时更方便,控制器也不用处理数据关联的细节。
4. 添加查询错误处理
你的代码里没有处理查询失败的情况,比如数据库连接异常、SQL语法错误等,建议加上错误处理逻辑,避免出现白屏或未知错误:
// 模型中的search_people方法添加错误处理 function search_people() { $this->db->select("registration,gender,profile_img,location"); $this->db->from('search_result'); $this->db->join('service...'); // 你的关联逻辑 $query = $this->db->get(); // 检查查询是否成功 if (!$query) { // 记录错误日志 log_message('error', '查询人员数据失败:' . $this->db->error()['message']); return FALSE; } return $query->result_array(); } // 控制器中处理查询失败的情况 function index() { $people = $this->M_results->search_people(); if (!$people) { $this->session->set_flashdata('error', '加载人员数据失败,请稍后重试'); redirect('error'); // 跳转到错误页面 } $skills = $this->M_results->get_skill($category_name); if (!$skills) { $this->session->set_flashdata('error', '加载技能数据失败,请稍后重试'); redirect('error'); } }
内容的提问来源于stack exchange,提问作者Shihas
相关产品推荐
相关产品推荐

