这篇文章主要介绍了PHP+Mysql树型结构(无限分类)数据库设计的2种方式实例,以及优劣分析、探讨,需要的朋友可以参考下
我们经常需要在关系型数据库中保存一些树状结构数据,比如分类、菜单、论坛帖子树状回复等。常用的方法有两种:
1. 领接表的方式;
2. 预排序遍历树方式;
假设树状结构如下图:
领接表方式
主要依赖于一个 parent 字段,用于指向上级节点,将相邻的上下级节点连接起来,id 为自动递增自动,parent_id 为上级节点的 id。一目了然,“Java”是“Language”的子节点。
我们要显示树,PHP 代码也可以很直观,代码如下:
复制代码 代码如下:
/**
* 获取父节点下的所有子节点
*
* @since 2011-05-18
*
* @param $parent_id 父节点 id,0 则显示整个树结构。
* @param $level 当前节点所处的层级,用于缩进显示节点。
* @return void
*/
function show_children ($parent_id = 0, $level = 0)
{
// 获取父节点下的所有子节点
$result = mysql_query('SELECT id, name FROM tree WHERE parent_id=' . intval($parent_id));
// 显示每个子节点
while ($row = mysql_fetch_array($result)) {
// 缩进显示
echo '
// 递归调用当前函数,显示再下一级的子节点
show_children($row['id'], $level + 1);
}
}
?>
想要显示整个树结构,调用 show_children()。想要显示“Database”子树,则调用 show_children(2),因为“Database”的 id 是 2。
还有一个经常用到的功能是获取节点路径,即给出一个节点,返回从根节点到当前节点的路径。用函数实现如下:
复制代码 代码如下:
/**
* @param $id 需要获取路径的当前节点的 id。
* @return array
*/
function get_path($id)
{
// 获取当前节点的父节点 id 和当前节点名
$result = mysql_query('SELECT parent_id, name FROM tree WHEREname'];
// 如果父节点非 0,即非根节点,则进行递归调用获取父节点的路径
if ($row['parent_id']) {
// 递归调用,获取父节点的路径,并且合并到当前路径数组的其它元素前边
$path = array_merge(get_path($row['parent_id']), $path);
}
return $path;
}
?>
想要获取“MySQL 5.0”的路径,调用 get_path(4),4 即是这个节点的 id。
领接表方式的优点在于容易理解,代码也比较简单明了。缺点则是递归中的 SQL 查询会导致负载变大,特别是需要处理比较大型的树状结构的时候,查询语句会随着层级的增加而增加,WEB 应用的瓶颈基本都在数据库方面,所以这是一个比较致命的缺点,直接导致树结构的扩展困难重重。
排序遍历树方式
现在我们来聊聊第二种方式─预排序遍历树方式(即通常所说的 MPTT,Modified Preorder Tree Traversal)。此算法是在第一种方式的基础之上,给每个节点增加一个左、右数字,用于标识节点的遍历顺序,如下图所示:
从根节点开始左边为 1,然后下一个节点的左边为 2,以此类推,到最低层节点之后,最低层节点的右边为其左边的数字加 1。顺着这些节点,我们可以很容易地遍历完整个树。根据上图,我们对数据表做一些改变,增加两个字段,lft 和 rgt 用于存储左右数字(由于 left 和 right 是 MySQL 的保留字,所以我们改用简写)。表中各行的内容也就变成了:
接下来看看显示树/子树是多么简单,只需要一条 SQL 语句即可,比如显示“Database”子树,则需要获取到“Database”的左右数字,左为 2,右为 11,那么 SQL 语句是:
复制代码 代码如下:
SELECT * FROM tree WHERE lft BETWEEN 2 AND 11;
SQL 语句是简单了,但我们所希望的缩进显示却是个问题。什么时候应该显示缩进?缩进多少单位?解决这个问题,需要使用堆栈,即后进先出(LIFO),每到一个节点,将其右边的数字压入堆栈中。我们知道,所有节点右边的值都比其父节点右边的值小,那么将当前节点右边的值和堆栈最上边的右边值进行比较,如果当前节点比堆栈最上边的值小,表示当前堆栈里边剩下的都是父节点了,这时可以显示缩进,,堆栈的元素数量即是缩进深度。PHP 代码实现如下:
复制代码 代码如下:
/**
* @param $root_id 需要显示的树/子树根节点 id。
*/
function show_tree($root_id = 1)
{
// 获取当前根节点的左右数值
$result = mysql_query('SELECT lft, rgt FROM tree WHERESELECT name, lft, rgt FROM tree WHERE lft BETWEEN '.$row['lft'].' AND '.$row['rgt'].' ORDER BY lft ASC');
// 显示树的每个节点
while ($row = mysql_fetch_array($result)) {
if (count($stack)>0) { //仅当堆栈非空的时候检测
// 如果当前节点右边的值比堆栈最上边的值大,则移除堆栈最上边的值,因为这个值对应的节点不是当前节点的父节点
while ($row['rgt'] > $stack[count($stack)-1]) {
array_pop($stack);
} //while 循环结束之后,堆栈里边只剩下当前节点的父节点了
}
// 现在可以显示缩进了
echo '
// 将当前的节点压入堆栈里边,为循环后边的节点缩进显示做好准备
array_push($stack, $row['rgt']);
}
}
?>
获取整个树调用 show_tree(),获取“Database”子树调用show_tree(2)。在这个函数中,我们总算不需要用到递归了,呵呵。
接下来是显示从根节点到某节点的路径,这比起领接表方式来说也简单了很多,只需要一句 SQL 就行,不用递归 比如获取“ORACLE”这个节点的路径,其左右值分别是 7 和 10,则 SQL 语句为:
复制代码 代码如下:
SELECT name FROM tree WHERE lft = 10 ORDER BY lft ASC;
PHP 函数实现如下:
复制代码 代码如下:

熱AI工具

Undresser.AI Undress
人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover
用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

Video Face Swap
使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱門文章

熱工具

EditPlus 中文破解版
體積小,語法高亮,不支援程式碼提示功能

MinGW - Minimalist GNU for Windows
這個專案正在遷移到osdn.net/projects/mingw的過程中,你可以繼續在那裡關注我們。 MinGW:GNU編譯器集合(GCC)的本機Windows移植版本,可自由分發的導入函式庫和用於建置本機Windows應用程式的頭檔;包括對MSVC執行時間的擴展,以支援C99功能。 MinGW的所有軟體都可以在64位元Windows平台上運作。

DVWA
Damn Vulnerable Web App (DVWA) 是一個PHP/MySQL的Web應用程序,非常容易受到攻擊。它的主要目標是成為安全專業人員在合法環境中測試自己的技能和工具的輔助工具,幫助Web開發人員更好地理解保護網路應用程式的過程,並幫助教師/學生在課堂環境中教授/學習Web應用程式安全性。 DVWA的目標是透過簡單直接的介面練習一些最常見的Web漏洞,難度各不相同。請注意,該軟體中

MantisBT
Mantis是一個易於部署的基於Web的缺陷追蹤工具,用於幫助產品缺陷追蹤。它需要PHP、MySQL和一個Web伺服器。請查看我們的演示和託管服務。

SecLists
SecLists是最終安全測試人員的伙伴。它是一個包含各種類型清單的集合,這些清單在安全評估過程中經常使用,而且都在一個地方。 SecLists透過方便地提供安全測試人員可能需要的所有列表,幫助提高安全測試的效率和生產力。清單類型包括使用者名稱、密碼、URL、模糊測試有效載荷、敏感資料模式、Web shell等等。測試人員只需將此儲存庫拉到新的測試機上,他就可以存取所需的每種類型的清單。