当前位置:网站首页>Data storage practice based on left-order traversal
Data storage practice based on left-order traversal
2022-08-05 02:33:00 【lishuangquan1987】
参考文章
超赞 ! A foreigner's design and implementation of a tree data table that avoids recursively querying all sub-departments!
But when it comes to practice,Found an error somewhere in this article:
It is updated first and then deleted,It is found that the update will also update the node rvalue of the node to be deleted.
所以正确的做法是:
删除对应的Sql:
SET @lft := 7;/*要删除的节点左值*/
SET @rgt := 8;/*要删除的节点右值*/
begin;
/*先删除节点*/
DELETE FROM department WHERE lft=@lft AND rgt=@rgt;
/*再更新节点 */
UPDATE department SET lft=lft-2 WHERE lft > @lft;
UPDATE department SET rgt=rgt-2 WHERE rgt > @lft;
/*删除影响行数为0时,必须回滚*/
commit;
/*rollback*/
实践
The technical background used
This paper is used in practicego语言1.18.1+gormv1.23.6+sqlitev1.3.5
This practice is to do a cloud configuration function.The order of nodes is as follows:
客户 -> 项目 -> stop -> 电脑
The effect displayed by the client is as follows:
The purpose of implementation is to store the software configuration of each computer according to the above nodes.
节点模型
type NodeInfo struct {
Id uint `gorm:"primary_key;Column:Id"`
Name string `gorm:"column:Name"`
Level uint `gorm:"column:Level"`
Left uint `gorm:"column:Left"`
Right uint `gorm:"column:Right"`
}
对于Level的定义:
- 1:客户
- 2:项目
- 3:stop
- 4:电脑
查询
Customer names are unique,不能重复,Other nodes can repeat.
Query customer node information by customer name:
func getCustomer(customer string) (*models.NodeInfo, error) {
info := &models.NodeInfo{
}
if err := databases.DB.Where("Name=? and Level=1", customer).First(info).Error; err != nil {
return nil, err
} else {
return info, nil
}
}
查询所有的客户节点:只需要查询Level=1即可
func getCustomers() ([]models.NodeInfo, error) {
infos := make([]models.NodeInfo, 0)
if err := databases.DB.Where("Level=1").Find(&infos).Error; err != nil {
return nil, err
} else {
return infos, nil
}
}
查询指定客户名称All project nodes under :
Get the client node first,Get the client's lvalue and rvalue,Then get all by lvalue and rvalue项目子节点
func getProjects(customer string) ([]models.NodeInfo, error) {
customerModel := &models.NodeInfo{
}
var err error
if customerModel, err = getCustomer(customer); err != nil {
return nil, err
}
infos := make([]models.NodeInfo, 0)
if err := databases.DB.Where("Level=2 and Left>? and Right<?", customerModel.Left, customerModel.Right).Find(&infos).Error; err != nil {
return nil, err
}
return infos, nil
}
查询stop、电脑与以上类似.
插入一个节点
func insertNode(name string, level uint, left uint) (*models.NodeInfo, error) {
model := &models.NodeInfo{
Name: name,
Level: level,
Left: uint(left),
Right: left + 1,
}
if err := databases.DB.Transaction(func(tx *gorm.DB) error {
if err := tx.Exec("update NodeInfo set Right=Right+2 where Right>=?", left).Error; err != nil {
return err
}
if err := tx.Exec("update NodeInfo set Left=Left+2 where Left>?", left).Error; err != nil {
return err
}
if err := tx.Create(model).Error; err != nil {
return err
}
return nil
}); err != nil {
return nil, err
}
return model, nil
}
步骤是:Update other nodes first,再插入节点
其中:nameis the name of the node to be insertedlevelis the level at which to insert the node,This determines whether to insert parallel nodes or child nodes,leftis the lvalue of the node to be inserted,通常为父节点或者左节点的右值+1
For example, when there is no node at all,To insert a customer name as AAA的节点:
insertNode("AAA",1,1)
比如在客户名称为 AAA,左值为1,右值为2Add a project name under the node of PPP的节点:
//项目节点:level为2,The left value is the client node“AAA”的右值+1
insertNode("PPP",2,3)
删除一个节点
func removeNode(model *models.NodeInfo) error {
return databases.DB.Transaction(func(tx *gorm.DB) error {
if err := tx.Delete(models.NodeInfo{
}, "Left=? and Right=?", model.Left, model.Right).Error; err != nil {
return err
}
if err := tx.Exec("update NodeInfo Set Left=Left-2 where Left>?", model.Left).Error; err != nil {
return err
}
if err := tx.Exec("update NodeInfo set Right=Right-2 where Right>?", model.Right).Error; err != nil {
return err
}
return nil
})
}
步骤是:先删除节点,Then update other nodes,Opposite of adding node operation,The delete node on the WeChat article is wrong!!!
注意:This function can only delete a single node with no children
批量删除节点
func removeNodes(ms []models.NodeInfo) error {
return databases.DB.Transaction(func(tx *gorm.DB) error {
for _, model := range ms {
if err := tx.Delete(models.NodeInfo{
}, "Left=? and Right=?", model.Left, model.Right).Error; err != nil {
return err
}
}
for _, model := range ms {
if err := tx.Exec("update NodeInfo Set Left=Left-2 where Left>?", model.Left).Error; err != nil {
return err
}
if err := tx.Exec("update NodeInfo set Right=Right-2 where Right>?", model.Left).Error; err != nil {
return err
}
}
return nil
})
}
注意:This function can delete nodes in batches though,但是要注意使用场景:When a parent node is selected,All child nodes under the parent node will be deleted,传入时,需要按照LevelFields are passed in descending order,否则会出错!
如下图所示:
When deleting a client node,All child nodes under the client node will be queried,Then follow the child nodesLevelSort incoming in descending order.
The code to delete the client node is as follows:
func removeCustomer(customer string) error {
info := &models.NodeInfo{
}
var err error
if info, err = getCustomer(customer); err != nil {
return err
}
//查询customerThe descendant node below,然后全部移除,Also remove the folder
infos := make([]models.NodeInfo, 0)
if err = databases.DB.Where("Left>=? and Left<=?", info.Left, info.Right).Find(&infos).Error; err != nil {
return err
}
//排序,Remove the bottom node first,Then remove the above node
linq.From(infos).OrderByDescending(func(i interface{
}) interface{
} {
return i.(models.NodeInfo).Level }).ToSlice(&infos)
if err = removeNodes(infos); err != nil {
return err
}
return nil
}
步骤是:Get the client node information first,Query all child nodes under the client node(包含自己),Then sort the nodes in descending order,调用removeNodes方法
总结
以上实践,It is indeed better than the traditional pass in terms of queryParentIdMuch better to relate,Avoid recursive queries,But inserting and deleting can be a little trickier,各有利弊,But left-order traversal is an innovative approach,It takes a lot of practice to feel its benefits
边栏推荐
- nodeJs--封装路由
- 如何逐步执行数据风险评估
- leetcode-对称二叉树
- 【LeetCode刷题】-数之和专题(待补充更多题目)
- 用@Mapper查询oracle的分区情况报错
- 从零到一快速学会三子棋
- 01 [Foreword Basic Use Core Concepts]
- 【日常训练】1403. 非递增顺序的最小子序列
- [C language] Detailed explanation of stacks and queues (define, destroy, and data operations)
- DAY23: Command Execution & Code Execution Vulnerability
猜你喜欢

nodeJs--encapsulate routing

云原生(三十二) | Kubernetes篇之平台存储系统介绍

lua学习
![01 [Foreword Basic Use Core Concepts]](/img/90/67537d5fad28d68766ca85b887839e.png)
01 [Foreword Basic Use Core Concepts]

sql语句多字段多个值如何进行排序

从零到一快速学会三子棋

C语言实现简单猜数字游戏

nodeJs--封装路由

J9数字货币论:web3的创作者经济是什么?

Unleashing the engine of technological innovation, Intel joins hands with ecological partners to promote the vigorous development of smart retail
随机推荐
Apache DolphinScheduler新一代分布式工作流任务调度平台实战-中
Go 微服务开发框架 DMicro 的设计思路
View handler stepping record
蚁剑高级模块开发
2022了你还不会『低代码』?数据科学也能玩转Low-Code啦!
Greenplum Database Fault Analysis - Can a Soft Connection Be Made to the Database Base Folder?
力扣-二叉树的前序遍历、中序遍历、后序遍历
[ROS] (10) ROS Communication - Service Communication
[Fortune-telling-60]: "The Soldier, the Tricky Way"-2-Interpretation of Sun Tzu's Art of War
1873. The special bonus calculation
Quickly learn chess from zero to one
常见的硬件延迟
J9数字货币论:web3的创作者经济是什么?
leetcode-另一棵树的子树
22-07-31周总结
627. 变更性别
特殊矩阵的压缩存储
如何模拟后台API调用场景,很细!
01 【前言 基础使用 核心概念】
select 标签自定义样式