一种使用mysql保存树形结构的方式 demo


建一个简单的表,结构如下,解释一下这三个字段的作用

  • id:每个record的唯一id
  • parentId:父节点的id,如果父节点是一级节点就为0
  • value:node的值

table

字段数据结构

type Node struct {
	Id string
	ParentId string
	Value string
}

func (*Node) TableName() string {
	return "node"
}

受用Node接受sql返回的数据

连接mysql

type Conn struct {
	db *gorm.DB
}

func (c *Conn) SelectNode(parentId string) *[]Node{
	var list []Node
	c.db.Raw("SELECT * FROM node WHERE parent_id = ?", parentId).Scan(&list)
	return &list
}

func connect() *gorm.DB{
	db, err := gorm.Open(mysql.Open("root:123456@tcp(127.0.0.1:3306)/node?charset=utf8mb4&parseTime=True&loc=Local"), &gorm.Config{})
	if err != nil{
		log.Print("connect to mysql error")
	}
	return db
}

用Conn接受返回的db对象,表结构比较简单,用SelectNode足够解决查询问题。

构造树形结构

把构造过程分为两部分,首先获取所有的root(parentId == 0)并放入Array中,人后在根据每个root的id递归构造子树

TreeNode是树形结构的基本组成,除了具有Node的基本属性还有children

type TreeNode struct {
	Node
	children *[]TreeNode
}

func buildRoot(conn *Conn) *[]TreeNode{
	var container []TreeNode
	list := *conn.SelectNode("0")
	for _, value := range list{
		tr := &TreeNode{
			Node: Node{
				Id: value.Id,
				ParentId: value.ParentId,
				Value: value.Value,
			},
		}
		container = append(container, *tr)
	}
	return &container
}

func build(container *[]TreeNode, conn *Conn) *[]TreeNode{
	for i, value := range *container{
		var children []TreeNode
		list := conn.SelectNode(value.Id)
		for _, node := range *list{
			children = append(children, TreeNode{
				Node: Node{Id: node.Id, ParentId: node.ParentId, Value:node.Value},
			})
			(*container)[i].children = &children
		}
		if value.children != nil{
			build(value.children, conn)
		}
	}
	return container
}

Author: Maple
Reprint policy: All articles in this blog are used except for special statements CC BY 4.0 reprint polocy. If reproduced, please indicate source Maple !
  TOC