目前我的代码(PHP)中包含太多SQL查询。例如...
// not a real example, but you get the idea...
$results = $db->GetResults("SELECT * FROM sometable WHERE iUser=$userid");
if ($results) {
// Do something
}
我正在研究使用存储过程来减少这种情况并使事情变得更加健壮,但我有一些担忧..
我在网站上使用了数百个不同的查询,其中很多都非常相似。当从上下文中删除所有这些查询(使用结果的代码)并将其放在数据库的存储过程中时,我应该如何管理这些查询?
答案 0 :(得分:29)
答案 1 :(得分:4)
首先,您应该在查询中使用占位符,而不是直接插入变量。 PDO / MySQLi允许您编写如下查询:
SELECT * FROM sometable WHERE iUser = ?
API会安全地将值替换为查询。
我也更喜欢在代码而不是数据库中查询。当查询与您的代码一起使用时,使用RCS要容易得多。
使用ORM时我有一条经验法则:如果我一次只使用一个实体,我将使用该界面。如果我正在汇总报告/处理记录,我通常会编写SQL查询来执行此操作。这意味着我的代码中的查询非常少。
答案 2 :(得分:3)
我不得不清理一个项目,其中有许多(重复/类似)查询充斥着注入漏洞。 我采取的第一步是使用占位符,并使用创建查询的对象/方法和源代码行标记每个查询。 (将PHP常量 METHOD 和 LINE 插入SQL注释行)
它看起来像这样:
- @Line:151 UserClass :: getuser():
SELECT * FROM USERS;
短时间记录所有查询为我提供了一些要合并查询的起点。 (还有哪里!)
答案 3 :(得分:3)
我将所有SQL移动到一个单独的Perl模块(.pm)许多查询可以重用相同的函数,但参数略有不同。
开发人员的一个常见错误是深入了解ORM库,参数化查询和存储过程。然后我们连续几个月工作以使代码“更好”,但它在开发方式中只是“更好”。你没有做任何新功能!
仅在代码中使用复杂性来满足客户需求。
答案 4 :(得分:2)
使用ORM包,任何一半体面的包都允许你
如果你有非常复杂的SQL,那么视图也很适合让它更适合应用程序的不同层。
答案 5 :(得分:2)
我们曾经处于类似的困境中。我们以超过50多种方式查询了一个特定的表格。
我们最终做的是创建一个包含WhereClause参数值的Fetch存储过程。 WhereClause是在Provider对象中构建的,我们采用了Facade设计模式,我们可以擦除它用于任何SQL注入攻击。
因此,就维护而言,它很容易修改。 SQL Server也是 chum ,并且缓存了动态查询的执行计划,因此整体性能非常好。
您必须根据自己的系统和需求确定性能缺点,但总而言之,这对我们来说非常好。
答案 6 :(得分:1)
有一些库,例如PEAR中的MDB2,使查询更容易和更安全。
不幸的是,设置它们可能有点罗嗦,有时您必须将相同的信息传递两次。我在几个项目中使用过MDB2,我倾向于在它周围写一个薄的贴面,特别是用于指定字段的类型。我通常会创建一个知道特定表及其列的对象,然后在调用MDB2查询函数时为我填充字段类型的辅助函数。
例如:
function MakeTableTypes($TableName, $FieldNames)
{
$Types = array();
foreach ($FieldNames as $FieldName => $FieldValue)
{
$Types[] = $this->Tables[$TableName]['schema'][$FieldName]['type'];
}
return $Types;
}
显然,这个对象有一个表名的映射 - >它知道的模式,只提取您指定的字段的类型,并返回适合与MDB2查询一起使用的匹配类型数组。
然后,MDB2(和类似的库)为你处理参数替换,所以对于更新/插入查询,你只需要从列名到值构建一个哈希/映射,并使用'autoExecute'函数来构建和执行相关的查询。例如:
function UpdateArticle($Article)
{
$Types = $this->MakeTableTypes($table_name, $Article);
$res = $this->MDB2->extended->autoExecute($table_name,
$Article,
MDB2_AUTOQUERY_UPDATE,
'id = '.$this->MDB2->quote($Article['id'], 'integer'),
$Types);
}
并且MDB2将构建查询,正确地转义所有内容等。
我建议使用MDB2测量性能,因为如果您没有运行PHP加速器,它会引入一些可能导致问题的代码。
正如我所说,设置开销一开始似乎令人生畏,但一旦完成,查询可以更简单/更符号来编写和(尤其)修改。我认为MDB2应该更多地了解你的模式,这会简化一些常用的API调用,但你可以通过自己封装模式来减少这种烦恼,如上所述,并提供简单的访问器函数来生成数组MDB2需要执行这些查询。
当然,如果你愿意的话,你可以使用query()函数将平面SQL查询作为字符串进行,所以你不必被迫切换到完整的'MDB2方式' - 你可以逐个尝试它,并且看你是否讨厌它。
答案 7 :(得分:0)
This other question也有一些有用的链接...
答案 8 :(得分:0)
我尝试使用相当通用的函数,只是传递它们之间的差异。这样,您只有一个函数来处理大多数数据库SELECT。显然你可以创建另一个函数来处理所有的INSERTS。
例如
function getFromDB($table, $wherefield=null, $whereval=null, $orderby=null) {
if($wherefield != null) {
$q = "SELECT * FROM $table WHERE $wherefield = '$whereval'";
} else {
$q = "SELECT * FROM $table";
}
if($orderby != null) {
$q .= " ORDER BY ".$orderby;
}
$result = mysql_query($q)) or die("ERROR: ".mysql_error());
while($row = mysql_fetch_assoc($result)) {
$records[] = $row;
}
return $records;
}
这只是我的头脑,但你明白了。要使用它,只需将函数传递给必要的参数:
例如
$blogposts = getFromDB('myblog', 'author', 'Lewis', 'date DESC');
在这种情况下, $ blogposts 将是一个数组数组,代表表的每一行。然后你可以直接使用foreach或直接引用数组:
echo $blogposts[0]['title'];
答案 9 :(得分:0)
使用像QCodo这样的ORM框架 - 您可以轻松映射现有数据库