当前位置:网站首页>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,再插入节点
其中:name
is the name of the node to be insertedlevel
is the level at which to insert the node,This determines whether to insert parallel nodes or child nodes,left
is 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,传入时,需要按照Level
Fields are passed in descending order,否则会出错!
如下图所示:
When deleting a client node,All child nodes under the client node will be queried,Then follow the child nodesLevel
Sort 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
边栏推荐
- LeetCode使用最小花费爬楼梯----dp问题
- Access Characteristics of Constructor under Inheritance Relationship
- 线性表的查找
- nodeJs--封装路由
- 1527. 患某种疾病的患者
- 01 【前言 基础使用 核心概念】
- How to simply implement the quantization and compression of the model based on the OpenVINO POT tool
- Greenplum Database Fault Analysis - Can a Soft Connection Be Made to the Database Base Folder?
- RAID disk array
- select 标签自定义样式
猜你喜欢
如何逐步执行数据风险评估
从零到一快速学会三子棋
Access Characteristics of Constructor under Inheritance Relationship
CPDA|运营人如何从负基础学会数据分析(SQL)
浅谈数据安全治理与隐私计算
Hypervisor related knowledge points
云原生(三十二) | Kubernetes篇之平台存储系统介绍
KingbaseES V8 GIS data migration solution (2. Introduction to the capabilities of Kingbase GIS)
DAY23:命令执行&代码执行漏洞
Live preview | 30 minutes started quickly!Look at credible distributed AI chain oar architectural design
随机推荐
The 20th day of the special assault version of the sword offer
Introduction to SDC
shell语句修改txt文件或者sh文件
Flink 1.15.1 集群搭建(StandaloneSession)
Common hardware delays
Domain Driven Design - MDD
ARM Mailbox
DAY22:sqli-labs 靶场通关wp(Less01~~Less20)
C language implements a simple number guessing game
How to simply implement the quantization and compression of the model based on the OpenVINO POT tool
SDC简介
Data to enhance Mixup principle and code reading
1873. The special bonus calculation
01 【前言 基础使用 核心概念】
What should I do if the self-incrementing id of online MySQL is exhausted?
the mechanism of ideology
力扣-二叉树的最大的深度
dmp(dump)转储文件
Semi-Decentralized Federated Learning for Cooperative D2D Local Model Aggregation
nodeJs--封装路由