本文将分为以下几个部分,从基础到进阶,并结合实例进行讲解:

- 核心基础:
$dsql对象详解 - 基础查询:
Execute()和GetOne() - 列表查询:
SetQuery()和Execute()的组合使用 - 进阶查询:
SelectSql()与原生 SQL - 查询实例:常见场景代码
- 查询结果集处理:
GetArray()和GetObject() - 安全与性能优化建议
核心基础:$dsql 对象详解
在进行任何查询之前,你必须获取 DedeCMS 的数据库操作对象,这个对象通常命名为 $dsql。
- 全局对象:在大多数情况下,你可以在任何文件中直接使用全局变量
$dsql。global $dsql;
- 独立对象:如果你在一个独立的 PHP 文件中(比如一个自定义的 API 或脚本),你需要先实例化它。
require_once(dirname(__FILE__)."/include/common.inc.php"); // 引入核心文件 $dsql = new DedeSql(false); // false 表示不连接后台数据库 // 或者直接使用 $dsql = $GLOBALS['dsql'];
$dsql 的主要特点:
- 安全性:自动对 SQL 语句中的特殊字符进行转义,防止 SQL 注入。
- 便捷性:提供了丰富的 API,无需手写复杂的 SQL 语句。
- 兼容性:底层使用 PDO,支持多种数据库(MySQL, SQLite 等)。
基础查询:Execute() 和 GetOne()
这两种方法用于执行单条、确定结果数量的 SQL 语句。
a) Execute() - 执行查询并获取结果集
当你需要获取多行数据时(比如查询某个分类下的所有文章),使用 Execute()。

语法:
$dsql->Execute('me', $sql);
$sql: 你的 SQL 查询语句。'me': 这是一个别名,用于在后续获取结果时标识这个结果集,通常使用'me'即可。
示例:查询 dede_archives 表中 typeid 为 1 的所有文章。
<?php
require_once(dirname(__FILE__)."/include/common.inc.php");
global $dsql;
// 1. 准备SQL语句
$sql = "SELECT id, title, pubdate FROM dede_archives WHERE typeid = 1 ORDER BY id DESC";
// 2. 执行查询
$dsql->Execute('me', $sql);
// 3. 遍历结果集
while($row = $dsql->GetArray('me'))
{
// $row 是一个关联数组,键名为字段名
$title = $row['title'];
$pubdate = date('Y-m-d H:i:s', $row['pubdate']);
echo "文章ID: {$row['id']}, 标题: {$title}, 发布时间: {$pubdate}<br />";
}
// 或者使用 GetObject()
$dsql->Execute('me', $sql);
while($row = $dsql->GetObject('me'))
{
// $row 是一个对象,属性名为字段名
echo "文章ID: {$row->id}, 标题: {$row->title}<br />";
}
?>
b) GetOne() - 获取单行单列数据
当你只需要查询一条记录,或者一个具体的值时(比如检查用户名是否存在),使用 GetOne()。
语法:
$row = $dsql->GetOne($sql);
$sql: 你的 SQL 查询语句。注意:这个 SQL 语句只能返回一行数据。
示例:检查 ID 为 100 的文章是否存在。
<?php
require_once(dirname(__FILE__)."/include/common.inc.php");
global $dsql;
// 1. 准备SQL语句
$sql = "SELECT id FROM dede_archives WHERE id = 100";
// 2. 执行查询,返回一个关联数组
$row = $dsql->GetOne($sql);
// 3. 判断结果
if(is_array($row))
{
echo "文章ID为 100 的文章存在!";
}
else
{
echo "文章ID为 100 的文章不存在。";
}
// 另一个例子:获取总文章数
$sql_count = "SELECT COUNT(*) as total FROM dede_archives";
$count_row = $dsql->GetOne($sql_count);
$total_articles = $count_row['total'];
echo "网站总共有 {$total_articles} 篇文章。";
?>
列表查询:SetQuery() 和 Execute() 的组合使用
这是 DedeCMS 分页查询的标准做法,它将 SQL 语句的构建和执行分离,非常灵活。
语法:
$dsql->SetQuery($sql); // 设置SQL模板
$dsql->Execute('me'); // 执行查询
示例:制作一个带分页的文章列表页面。
<?php
require_once(dirname(__FILE__)."/include/common.inc.php");
global $dsql;
// 1. 获取分页参数
$page = isset($page) ? intval($page) : 1;
$pagesize = 10; // 每页显示10条
// 2. 构建核心查询SQL(不含 LIMIT)
$sql = "SELECT id, title, litpic FROM dede_archives ORDER BY id DESC";
// 3. 使用 $dsql 的分页函数
$totalResult = $dsql->ExecuteNoneQuery($sql); // 先执行一次以获取总数
$totalRows = $dsql->GetTotalRow($totalResult);
$pages = ceil($totalRows / $pagesize);
// 4. 使用 SetQuery 和 Execute 进行分页查询
$dsql->SetQuery($sql);
$dsql->Execute('me', $sql, ($page - 1) * $pagesize, $pagesize); // 第四个参数是分页参数
// 5. 遍历输出
while($row = $dsql->GetArray('me'))
{
echo "<a href='/plus/view.php?aid={$row['id']}'>{$row['title']}</a><br />";
}
// 6. 调用 DedeCMS 的分页函数
// 需要先引入文件 include/arc.partview.class.php
$plist = '';
if($pages > 1)
{
$plist = showpage($totalRows, $pagesize, $page, "?page=");
}
echo $plist;
?>
注意:在实际开发中,分页功能通常由 DedeCMS 的系统标签
{dede:list}完成,但在二次开发中,当需要自定义复杂的列表逻辑时,手动分页是必要的。
进阶查询:SelectSql() 与原生 SQL
当你需要执行复杂的、不涉及返回结果集的 SQL 语句时(如 INSERT, UPDATE, DELETE),或者想完全控制 SQL 语句时,可以使用以下方法。
a) ExecuteNoneQuery() - 执行无结果集的 SQL
用于执行 INSERT, UPDATE, DELETE 等操作。
示例:更新一篇文章的点击量。
<?php
require_once(dirname(__FILE__)."/include/common.inc.php");
global $dsql;
$aid = 123; // 文章ID
$dsql->ExecuteNoneQuery("UPDATE dede_archives SET click = click + 1 WHERE id = {$aid}");
echo "点击量更新成功!";
?>
b) SelectSql() - 获取完整的 SQL 语句
这个方法本身不执行查询,而是返回一个经过 $dsql 处理(如安全过滤)后的完整 SQL 字符串,你可以将它用于调试,或者与其他数据库操作工具配合使用。
示例:构建一个安全的查询语句。
<?php
require_once(dirname(__FILE__)."/include/common.inc.php");
global $dsql;
$keyword = "织梦"; // 用户输入的关键词
$field = "title"; // 搜索字段
// 构建SQL模板
$sql = "SELECT id, title FROM dede_archives WHERE {$field} LIKE '%".$keyword."%'";
// 获取处理后的SQL字符串(用于调试)
$safe_sql = $dsql->SelectSql($sql);
echo "即将执行的SQL是: " . $safe_sql . "<br />";
// 执行查询
$dsql->Execute('me', $safe_sql);
while($row = $dsql->GetArray('me'))
{
echo "找到文章: " . $row['title'] . "<br />";
}
?>
查询实例:常见场景代码
场景1:获取指定栏目下的所有子栏目
global $dsql;
$topid = 2; // 假设父栏目ID为2
$sql = "SELECT id, typename, reid FROM dede_arctype WHERE topid = {$topid} ORDER BY sortrank";
$dsql->Execute('me', $sql);
while($row = $dsql->GetArray('me'))
{
echo "栏目ID: {$row['id']}, 名称: {$row['typename']}<br />";
}
场景2:获取某篇文章的所有标签
这需要关联 dede_taglist 和 dede_tagindex 表。
global $dsql;
$aid = 100; // 文章ID
$sql = "SELECT t.tagname FROM dede_taglist AS tl
LEFT JOIN dede_tagindex AS t ON tl.tid = tid
WHERE tl.aid = {$aid}";
$dsql->Execute('me', $sql);
$tags = array();
while($row = $dsql->GetArray('me'))
{
$tags[] = $row['tagname'];
}
echo "文章标签: " . implode(', ', $tags);
查询结果集处理
$dsql->GetArray('me'): 将当前行数据作为一个关联数组返回。$row['fieldname']。$dsql->GetObject('me'): 将当前行数据作为一个对象返回。$row->fieldname。$dsql->GetOne(): 已经介绍过,直接获取单行数据。$dsql->MoveNext(): 将指针移动到下一行,通常在while循环中使用,但GetArray/GetObject内部已经调用了它,所以一般无需手动调用。
安全与性能优化建议
-
永远不要相信用户输入:所有来自用户的变量(如 GET, POST)都必须进行过滤和验证。
// 错误示范(直接拼接) $id = $_GET['id']; $sql = "SELECT * FROM dede_archives WHERE id = $id"; // 正确示范(使用 $dsql 自动转义) $id = intval($_GET['id']); // 先转成整数 $sql = "SELECT * FROM dede_archives WHERE id = {$id}"; $dsql->Execute('me', $sql);$dsql会在执行时自动对变量进行转义,但养成手动intval()等习惯能提供额外保障。 -
为常用查询字段建立索引:
dede_archives表的typeid,arcrank,pubdate等字段,如果经常作为WHERE或ORDER BY的条件,建立索引可以极大提升查询速度。 -
*避免使用 `SELECT `**:只查询你需要的字段,可以减少数据传输量,提高查询效率。
-
合理使用缓存:对于不经常变化的数据列表(如热门文章、推荐栏目),可以使用 DedeCMS 的缓存机制或 Memcached/Redis 进行缓存,避免频繁查询数据库。
| 方法 | 用途 | 返回值 | 适用场景 |
|---|---|---|---|
Execute() |
执行查询,获取结果集 | 结果集资源 | 获取多行数据,如列表、分类等 |
GetOne() |
执行查询,获取单行数据 | 关联数组 | 检查记录是否存在、获取单个值(如总数) |
SetQuery() |
设置SQL模板(用于分页) | 无 | 与 Execute() 配合,实现高效的分页查询 |
ExecuteNoneQuery() |
执行无结果集的SQL | 影响的行数 | INSERT, UPDATE, DELETE 操作 |
SelectSql() |
获取处理后的SQL字符串 | 字符串 | 调试SQL,或与其他数据库工具交互 |
掌握了 $dsql 的这些核心方法,你就可以应对 DedeCMS 二次开发中绝大多数的数据库查询需求了,关键在于理解每种方法的用途,并结合具体场景选择最合适的方案。
