织梦CMS的数据库操作主要分为两种方式:

(图片来源网络,侵删)
- 使用Dede内置函数(推荐):这是最安全、最规范的方式,利用了织梦封装好的
dedesql类,可以有效防止SQL注入,并且代码风格与织梦系统保持一致。 - 使用原生PHP的MySQL函数(不推荐):直接使用
mysql_query()等旧版函数,这种方式已经过时,且存在安全风险,不推荐在二次开发中使用。
使用Dede内置函数($dsql 或 $db)
这是织梦二次开发的核心,织梦的全局对象 $dsql 和 $db 就是操作数据库的利器。$dsql 是最常用、最强大的对象。
$dsql 对象简介
$dsql 是 DedeSql 类的一个实例,它封装了数据库的连接、查询、增、删、改等操作,在织梦的PHP文件中,它通常是全局可用的。
基本用法示例
假设我们要操作名为 dede_archives 的文章主表。
a) 执行一个查询(Execute() 方法)
这是最常用的查询方法,用于执行 SELECT 语句。

(图片来源网络,侵删)
<?php
// 引入全局数据库对象(如果当前文件没有,通常需要引入:require_once(dirname(__FILE__)."/include/common.inc.php");
// 在织梦的很多页面中,$dsql 已经是全局变量了
// 1. 准备SQL语句
// 注意:表名前缀 `{dede_}` 是必须的,这样系统会自动替换为你真实的表前缀
$sql = "SELECT id, title, typeid FROM `{dede_archives}` ORDER BY id DESC LIMIT 10";
// 2. 执行查询
$dsql->Execute('me', $sql);
// 3. 遍历结果集
// Execute() 返回一个结果集对象,我们可以用下面的方式循环获取数据
while ($row = $dsql->GetArray('me')) {
// $row 是一个关联数组,键名是字段名
echo "文章ID: " . $row['id'] . "<br>";
echo "文章标题: " . $row['title'] . "<br>";
echo "分类ID: " . $row['typeid'] . "<hr>";
}
// 4. 释放结果集(虽然脚本结束时会自动释放,但良好习惯是手动释放)
$dsql->FreeResult('me');
?>
Execute() 方法详解:
$dsql->Execute('别名', 'SQL语句')- 第一个参数
'别名'是给这个查询结果集起一个别名,在后续的GetArray()或GetObject()中需要用到这个别名来区分不同的查询结果。 - 第二个参数就是标准的SQL查询语句。
b) 获取单条记录(简化方法)
如果只需要查询一条记录,可以使用更简化的方法。
GetOne():获取一条记录,并以关联数组的形式返回。
<?php
$sql = "SELECT title FROM `{dede_archives}` WHERE id = 100";
$row = $dsql->GetOne($sql);
// $row 直接就是数组
if (is_array($row)) {
echo "文章标题是: " . $row['title'];
} else {
echo "未找到ID为100的文章。";
}
?>
GetOneRow():功能与 GetOne() 类似,但返回的是数字索引数组(较少使用)。

(图片来源网络,侵删)
GetObject():获取一条记录,并以对象的形式返回。
<?php
$sql = "SELECT title FROM `{dede_archives}` WHERE id = 100";
$object = $dsql->GetObject($sql);
// $row 是一个对象,通过 -> 访问属性
if ($object) {
echo "文章标题是: " . $object->title;
} else {
echo "未找到ID为100的文章。";
}
?>
c) 执行更新、插入、删除(ExecuteNoneQuery() 方法)
这类操作不需要返回结果集,只需要执行SQL语句。
<?php
// 1. 更新操作
$update_sql = "UPDATE `{dede_archives}` SET title = '新标题' WHERE id = 100";
$dsql->ExecuteNoneQuery($update_sql);
echo "更新操作执行完毕,影响的行数: " . $dsql->GetAffectedRows() . "<br>";
// 2. 插入操作
$insert_sql = "INSERT INTO `{dede_archives}` (title, typeid, arcpinyin, pubdate, senddate) VALUES ('测试文章', 1, 'test', NOW(), NOW())";
$dsql->ExecuteNoneQuery($insert_sql);
echo "插入操作执行完毕,最后插入的ID: " . $dsql->GetLastID() . "<br>";
// 3. 删除操作
$delete_sql = "DELETE FROM `{dede_archives}` WHERE id = 101";
$dsql->ExecuteNoneQuery($delete_sql);
echo "删除操作执行完毕,影响的行数: " . $dsql->GetAffectedRows() . "<br>";
?>
d) 获取查询结果行数
<?php
$sql = "SELECT id FROM `{dede_archives}`";
$dsql->Execute('me', $sql);
$totalRows = $dsql->GetTotalRow('me'); // 使用之前Execute时定义的别名
echo "总共有 " . $totalRows . " 篇文章。";
?>
e) 安全查询(GetOne() 等方法的自动转义)
使用 $dsql 的 GetOne(), GetArray(), Execute() 等方法时,如果SQL语句中包含变量,必须使用 empirecms 提供的函数进行转义,以防止SQL注入。
// 错误示范!有SQL注入风险!
$id = $_GET['id'];
$sql = "SELECT title FROM `{dede_archives}` WHERE id = $id"; // 危险!
// 正确示范
$id = intval($_GET['id']); // 最安全的方式,如果是数字ID
// 或者使用织梦的过滤函数
$id = $dsql->GetOne("SELECT id FROM `{dede_member}` WHERE userid='".$dsql->EscapeString($_GET['user'])."'"); // 如果是字符串
$sql = "SELECT title FROM `{dede_archives}` WHERE id = $id"; // $id 已经是安全的整数
$row = $dsql->GetOne($sql);
?>
$dsql->EscapeString() 是 $dsql 对象内置的转义函数,会对字符串进行安全处理。
使用原生PHP的MySQL函数($db 对象)
这种方式是织梦早期版本遗留下来的,功能较少,且 $db 对象没有 $dsql 那么完善的安全机制。除非有特殊需求,否则应尽量避免使用。
$db 对象通常是 mysql 或 mysqli 的一个连接资源。
基本用法示例
<?php
// 1. 执行查询
$sql = "SELECT id, title FROM `{dede_archives}` LIMIT 5";
$rs = $db->Execute($sql); // $db->Execute() 返回一个结果集对象
// 2. 遍历结果集
while (!$rs->EOF) { // 使用 EOF (End of File) 判断是否结束
// rs->fields 是一个数字索引数组
echo "ID: " . $rs->fields[0] . ", 标题: " . $rs->fields[1] . "<br>";
// 移动到下一行
$rs->MoveNext();
}
// 3. 获取字段值(通过字段名)
$rs->MoveFirst(); // 回到第一行
echo "第一篇文章的标题是: " . $rs->fields['title'];
// 4. 释放结果集
$rs->Close();
?>
执行更新、插入、删除
<?php
$sql = "UPDATE `{dede_archives}` SET title = '旧标题' WHERE id = 100";
$db->Execute($sql); // 直接执行,不返回结果
?>
最佳实践与注意事项
- 优先使用
$dsql:在99%的情况下,都应使用$dsql对象进行数据库操作。 - 表名加前缀:在SQL语句中写表名时,务必使用
{dede_}作为前缀,如{dede_archives},这样无论用户安装时设置什么前缀,代码都能正常工作。 - 变量过滤:所有来自用户输入的数据(GET, POST, COOKIE等)都不能直接拼接到SQL语句中,必须使用
intval()(对于数字) 或$dsql->EscapeString()(对于字符串) 进行过滤。 - 及时释放资源:对于查询操作,当结果集使用完毕后,调用
$dsql->FreeResult('别名')或$rs->Close()来释放数据库资源,尤其是在循环或大量查询时,这可以避免服务器资源耗尽。 - 错误处理:
$dsql提供了简单的错误处理机制,如果SQL执行出错,可以通过$dsql->GetError()获取错误信息,在开发阶段可以开启调试,方便排查问题。 - 事务处理:织梦也支持事务操作,确保一组SQL语句要么全部成功,要么全部失败,这在处理关联数据(如发布文章时同时插入文章、栏目、附加表等)时非常有用。
事务示例:
<?php
$dsql->SetQuery("INSERT INTO dede_archives...");
$dsql->Execute('add1');
$dsql->SetQuery("INSERT INTO dede_addonarticle...");
$dsql->Execute('add2');
// 如果上面两条都成功,则提交事务
if (!$dsql->GetError() && $dsql->GetAffectedRows('add1') > 0 && $dsql->GetAffectedRows('add2') > 0) {
$dsql->Commit();
} else {
// 如果有任何一条失败,则回滚事务
$dsql->Rollback();
}
?>
| 操作类型 | 推荐方法 ($dsql) |
说明 |
|---|---|---|
| 查询多条记录 | $dsql->Execute('别名', $sql) + $dsql->GetArray('别名') |
最灵活,适用于复杂查询 |
| 查询单条记录 | $dsql->GetOne($sql) |
返回关联数组,最常用 |
| 查询单条记录(对象) | $dsql->GetObject($sql) |
返回对象,面向对象风格 |
| 执行增/删/改 | $dsql->ExecuteNoneQuery($sql) |
不返回结果集 |
| 获取影响行数 | $dsql->GetAffectedRows() |
配合 ExecuteNoneQuery 使用 |
| 获取最后插入ID | $dsql->GetLastID() |
配合 INSERT 操作使用 |
| 字符串转义 | $dsql->EscapeString($str) |
防止SQL注入,必须使用 |
掌握 $dsql 的使用,是进行织梦CMS二次开发的基础和关键。
