您现在的位置是:主页 > news > 网站seo三要素/简述seo的优化流程

网站seo三要素/简述seo的优化流程

admin2025/4/28 8:52:47news

简介网站seo三要素,简述seo的优化流程,济南 制作网站 公司,企业网站 响应式 案例数据表之间关联关系和关联查询由 学院君 创建于5个月前, 最后更新于 5个月前版本号 #3961 views0 likes0 collects关联关系简介MySQL 之所以被称之为关系型数据库,是因为可以基于外键定义数据表之间的关联关系,日常开发常见的关联关系如下所示&#xff1…

网站seo三要素,简述seo的优化流程,济南 制作网站 公司,企业网站 响应式 案例数据表之间关联关系和关联查询由 学院君 创建于5个月前, 最后更新于 5个月前版本号 #3961 views0 likes0 collects关联关系简介MySQL 之所以被称之为关系型数据库,是因为可以基于外键定义数据表之间的关联关系,日常开发常见的关联关系如下所示&#xff1…

数据表之间关联关系和关联查询

由 学院君 创建于5个月前, 最后更新于 5个月前

版本号 #3

961 views

0 likes

0 collects

关联关系简介

MySQL 之所以被称之为关系型数据库,是因为可以基于外键定义数据表之间的关联关系,日常开发常见的关联关系如下所示:

一对一:一张表的一条记录对应另一张表的一条记录,比如用户表与用户资料表

一对多:一张表的一条记录对应另一张表的多条记录,比如用户表与文章表、文章表与评论表

多对一:一张表的多条记录归属另一张表的一条记录(一对多的逆向操作)

多对多:一张表的多条记录归属另一张表的多条记录,此时仅仅基于两张表的字段已经无法定义这种关联关系,需要借助中间表来定义,比如文章表与标签表往往是这种关联

我们在上篇教程已经介绍了 Go 语言中基于第三方包 go-sql-driver/mysql 对单个数据表的增删改查操作,接下来我们来看看如何基于这个包对关联表进行操作。

新建评论表

为了方便演示,我们在 test_db 数据库中新建一张评论表 comments:

CREATE TABLE `comments` (

`id` bigint unsigned NOT NULL AUTO_INCREMENT,

`content` text COLLATE utf8mb4_unicode_ci,

`author` varchar(30) COLLATE utf8mb4_unicode_ci DEFAULT NULL,

`post_id` bigint unsigned DEFAULT NULL,

PRIMARY KEY (`id`),

FOREIGN KEY fk_post_id(`post_id`) REFERENCES posts(`id`) ON DELETE CASCADE

) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

这里我们创建了一个外键将 comments 表的 post_id 字段和 posts 表的 id 字段关联起来,并且通过 ON DELETE CASCADE 声明将两张表级联起来:当删除 posts 表中的某条记录时,自动删除 comments 中与之关联的评论记录(如果省略这个声明,则不能直接删除 posts 表中有 comments 关联依赖的记录)。

我们在 posts 和 comments 插入两条记录,这两条记录通过 comments.post_id 建立了外键关联:

703355959ac4798caa2e5612637e1669.png

6cce2bfc8b9c6979d7df3cfde8ad9b5c.png

此时,如果删除 posts 表中的记录,刷新 comments 表,会发现 comments 表对应记录也被清空,说明外键关联生效。

编写示例代码

接下来,我们编写一段示例代码演示如何在 Go 语言中通过 go-sql-driver/mysql 包对文章表和评论表进行关联查询。

新建一个 mysql 子目录来存放示例代码,这一次,我们通过拆分不同操作业务逻辑到不同文件来构建这个示例程序。

初始化连接

在 mysql 目录下新建一个 conn.go 编写数据库连接代码:

package main

import (

"database/sql"

_ "github.com/go-sql-driver/mysql"

)

var Db *sql.DB

// 初始化数据库连接

func init() {

var err error

Db, err = sql.Open("mysql", "root:root@/test_db?charset=utf8mb4&parseTime=true")

if err != nil {

panic(err)

}

}

注意到 Db 变量首字母大写了,因此一旦初始化之后,就可以在当前包下的任何文件中直接引用了。

迁移文章增删改查代码

将 posts 表增删改查操作拆分到独立的 post.go,并且在 Post 结构体中引入 Comments []Comment 属性存放关联的评论信息:

package main

type Post struct {

Id int

Title string

Content string

Author string

Comments []Comment

}

func Posts(limit int) (posts []Post, err error) {

stmt, err := Db.Prepare("select id, title, content, author from posts limit ?")

if err != nil {

panic(err)

}

defer stmt.Close()

rows, err := stmt.Query(limit)

if err != nil {

panic(err)

}

for rows.Next() {

post := Post{}

err = rows.Scan(&post.Id, &post.Title, &post.Content, &post.Author)

if err != nil {

panic(err)

}

posts = append(posts, post)

}

return

}

func GetPost(id int) (post Post, err error) {

post = Post{}

err = Db.QueryRow("select id, title, content, author from posts where id = ?", id).

Scan(&post.Id, &post.Title, &post.Content, &post.Author)

// 查询与之关联的 comments 记录

rows, err := Db.Query("select id, content, author from comments where post_id = ?", post.Id)

for rows.Next() {

comment := Comment{Post: &post}

err = rows.Scan(&comment.Id, &comment.Content, &comment.Author)

if err != nil {

return

}

post.Comments = append(post.Comments, comment)

}

rows.Close()

return

}

func (post *Post) Create() (err error) {

sql := "insert into posts (title, content, author) values (?, ?, ?)"

stmt, err := Db.Prepare(sql)

if err != nil {

panic(err)

}

defer stmt.Close()

res, err := stmt.Exec(post.Title, post.Content, post.Author)

if err != nil {

panic(err)

}

postId, _ := res.LastInsertId()

post.Id = int(postId)

return

}

func (post *Post) Update() (err error) {

stmt, err := Db.Prepare("update posts set title = ?, content = ?, author = ? where id = ?")

if err != nil {

return

}

stmt.Exec(post.Title, post.Content, post.Author, post.Id)

return

}

func (post *Post) Delete() (err error) {

stmt, err := Db.Prepare("delete from posts where id = ?")

if err != nil {

return

}

stmt.Exec(post.Id)

return

}

我们在 GetPost 方法中获取单条文章记录后,再通过对应文章 ID 进行数据库查询获取相关评论信息存放到 post 对象的 Comments 属性中,这样就可以通过该属性获取文章的评论数据了。

定义评论相关操作

紧接着创建 comment.go 定义 Comment 结构体及新建评论方法:

package main

import "errors"

type Comment struct {

Id int

Content string

Author string

Post *Post

}

func (comment *Comment) Create() (err error) {

if comment.Post == nil {

err = errors.New("Post not found")

return

}

sql := "insert into comments (content, author, post_id) values (?, ?, ?)"

res, err := Db.Exec(sql, comment.Content, comment.Author, comment.Post.Id)

if err != nil {

return

}

commentId, _ := res.LastInsertId()

comment.Id = int(commentId)

return

}

在 Comment 中,可以通过 Post *Post 指针引用其所属的文章对象。

整体测试代码

最后编写 main.go 测试上述关联查询:

package main

import (

"fmt"

)

func main() {

// 插入文章记录

post := Post{Title: "Golang 数据库编程", Content: "通过 go-sql-driver/mysql 包进行表之间的关联查询", Author: "学院君"}

post.Create()

// 插入评论记录

comment1 := Comment{Content: "测试评论1", Author: "学院君", Post: &post}

comment1.Create()

comment2 := Comment{Content: "测试评论2", Author: "学院君", Post: &post}

comment2.Create()

// 查询文章评论信息

mysqlPost, _ := GetPost(post.Id)

fmt.Println(mysqlPost)

fmt.Println(mysqlPost.Comments)

fmt.Println(mysqlPost.Comments[0].Post)

}

我们在 Post 和 Comment 结构体中分别通过 Comments 切片(数组指针)和 Post 指针定义两者之间的一对多和多对一关联,然后在查询文章记录的 GetPost 方法中编写通过 Post ID 查询关联 Comment 记录的代码,在创建 Comment 的时候,也要确保对应的 Post 字段不为空,即 post_id 字段不为空,这样就将两者通过代码关联起来了。

编译 mysql 这个包,并运行生成的二进制可执行程序,输出结果如下:

08140604c3a6e35bda95d4918b0e12cc.png

表明关联查询成功。

虽然我们已经构建起关联关系,但是全靠自己撸代码有点麻烦,而且随着应用的增长,这种复杂度会越来越大。我们可以通过 ORM 类来简化这个流程,目前 Go 语言中最流行的 ORM 实现非 GORM 莫属,下篇教程,学院君就来给大家介绍 GORM 的基本使用。