当前位置:网站首页>基于左序遍历的数据存储实践
基于左序遍历的数据存储实践
2022-08-05 02:30:00 【lishuangquan1987】
参考文章
超赞 ! 老外的一种避免递归查询所有子部门的树数据表设计与实现!
但是实践的时候,发现这篇文章有个地方有错误:
它是先更新再删除,发现更新会把要删除节点的节点右值也更新掉。
所以正确的做法是:
删除对应的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*/
实践
使用的技术背景
本文实践采用go语言1.18.1+gormv1.23.6+sqlitev1.3.5
本次实践是想做一个云配置功能。节点顺序如下:
客户 -> 项目 -> 站别 -> 电脑
客户端展示的效果如下:
实现的目的是按照如上的节点去储存每个电脑的软件配置。
节点模型
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:站别
- 4:电脑
查询
客户名称是唯一的,不能重复,其他节点可以重复。
按照客户名称查询客户节点信息:
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
}
}
查询指定客户名称下的所有项目节点:
先获取客户节点,拿到客户的左值与右值,然后通过左值与右值获取所有的项目子节点
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
}
查询站别、电脑与以上类似。
插入一个节点
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
}
步骤是:先更新其他节点,再插入节点
其中:name为要插入节点的名称level为要插入节点的级别,这决定着是插入平行节点还是子节点,left为要插入节点的左值,通常为父节点或者左节点的右值+1
比如一个节点都没有的时候,要插入一个客户名称为AAA的节点:
insertNode("AAA",1,1)
比如在客户名称为 AAA,左值为1,右值为2的节点下增加一个项目名称为PPP的节点:
//项目节点:level为2,左值为客户节点“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
})
}
步骤是:先删除节点,再更新其他节点,与增加节点操作相反,微信文章上的删除节点是错误的!!!
注意:此函数只能删除没有子节点的单个节点
批量删除节点
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
})
}
注意:此函数虽然可以批量删除节点,但是要注意使用场景:当选中某个父节点时,父节点下的所有子节点都会被删除,传入时,需要按照Level字段降序排列传入,否则会出错!
如下图所示:
当删除客户节点时,会查询客户节点下的所有子节点,然后把子节点按照Level降序排列传入。
删除客户节点的代码如下:
func removeCustomer(customer string) error {
info := &models.NodeInfo{
}
var err error
if info, err = getCustomer(customer); err != nil {
return err
}
//查询customer下的子孙节点,然后全部移除,还要移除文件夹
infos := make([]models.NodeInfo, 0)
if err = databases.DB.Where("Left>=? and Left<=?", info.Left, info.Right).Find(&infos).Error; err != nil {
return err
}
//排序,先移除最下面的节点,再移除上面的节点
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
}
步骤是:先获取客户节点信息,查询客户节点下的所有子节点(包含自己),然后降序排列节点,调用removeNodes方法
总结
以上实践,在查询方面确实比传统的通过ParentId来关联好的多,避免了递归查询,但是插入和删除会麻烦一些,各有利弊,但是左序遍历是一种创新的做法,多实践才能感觉到它的好处
边栏推荐
- Greenplum数据库故障分析——能对数据库base文件夹进行软连接嘛?
- 如何基于OpenVINO POT工具简单实现对模型的量化压缩
- Industry case | insurance companies of the world's top 500 construction standards can be used to drive the business analysis system
- ARM Mailbox
- C学生管理系统 指定位置插入学生节点
- 直播预告|30分钟快速入门!来看可信分布式AI链桨的架构设计
- dotnet 6 为什么网络请求不跟随系统网络代理变化而动态切换代理
- 02 [Development Server Resource Module]
- LPQ (local phase quantization) study notes
- C学生管理系统 据学号查找学生节点
猜你喜欢

特殊矩阵的压缩存储

1349. Maximum number of students taking the exam Status Compression

树表的查找

【MySQL系列】- LIKE查询 以%开头一定会让索引失效吗

【LeetCode刷题】-数之和专题(待补充更多题目)
![[LeetCode Brush Questions] - Sum of Numbers topic (more topics to be added)](/img/ee/6b52072c841af99488dc0c1141c74c.png)
[LeetCode Brush Questions] - Sum of Numbers topic (more topics to be added)

继承关系下构造方法的访问特点

KingbaseES V8 GIS data migration solution (2. Introduction to the capabilities of Kingbase GIS)

Unleashing the engine of technological innovation, Intel joins hands with ecological partners to promote the vigorous development of smart retail

优化Feed流遭遇拦路虎,是谁帮百度打破了“内存墙”?
随机推荐
继承关系下构造方法的访问特点
常见的硬件延迟
力扣-二叉树的最大的深度
使用OpenVINO实现飞桨版PGNet推理程序
HOG feature study notes
Domain Driven Design - MDD
RAID disk array
Opening - Open a new .NET modern application development experience
Live preview | 30 minutes started quickly!Look at credible distributed AI chain oar architectural design
C student management system Find student nodes based on student ID
Industry case | insurance companies of the world's top 500 construction standards can be used to drive the business analysis system
C student management system head to add a student node
英特尔 XDC 2022 精彩回顾:共建开放生态,释放“基建”潜能
select tag custom style
[Unity Entry Plan] Handling of Occlusion Problems in 2D Games & Pseudo Perspective
迁移学习——Distant Domain Transfer Learning
【MySQL系列】- LIKE查询 以%开头一定会让索引失效吗
DAY22: sqli-labs shooting range clearance wp (Less01~~Less20)
Simple implementation of YOLOv7 pre-training model deployment based on OpenVINO toolkit
02 [Development Server Resource Module]