IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 大数据 -> gorm数据库是否需要设置外键 -> 正文阅读

[大数据]gorm数据库是否需要设置外键

结论

gorm一对多官方文档

这里先说结论,gorm使用联合查询时不需要强制设置外键;但是从官方文档上来看,貌似关联查询必须建立外键,但其实是不需要设置外键的.代码会拿一对多进行举例;

设置外键的缺点

  1. 性能影响: 大型互联网项目或者分布式项目,进行更新操作时外键会影响数据库的性能
  2. 强耦合: 如果数据库中存在外键,会导致表与表之间的强耦合;其实可以再物理上删除外键;逻辑上还是存在的.(举个例子:用户表与信用卡表;信用卡表是有user_id这个字段的;我们再查询的时候还是通过user_id字段进行查询,但是表中并不会存在外键进行关联)
  3. 热更新: 如果数据库存在外键,会导致新更新的代码无法运行,会有产生冲突,sql报错的隐患
  4. 分库分表难度增加: 外键会导致分库分表难度增加(举个例子:用户表与信用卡表之间有外键关联,如果需要做分库,由于有外键的存在,是没有办法实现分布操作的)

sql

CREATE TABLE `credit_card` (
  `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
  `created_at` datetime(3) DEFAULT NULL,
  `updated_at` datetime(3) DEFAULT NULL,
  `deleted_at` datetime(3) DEFAULT NULL,
  `number` varchar(30) NOT NULL,
  `user_id` bigint(20) unsigned DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `idx_credit_card_deleted_at` (`deleted_at`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

CREATE TABLE `user` (
  `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
  `created_at` datetime(3) DEFAULT NULL,
  `updated_at` datetime(3) DEFAULT NULL,
  `deleted_at` datetime(3) DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `idx_user_deleted_at` (`deleted_at`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

代码

model

package model

import "gorm.io/gorm"

type User struct {
	gorm.Model
	CreditCards []*CreditCard `gorm:"foreignKey:UserId"`
}

type CreditCard struct {
	gorm.Model
	Number string `gorm:"number;type:varchar(30);not null"`
	UserId uint
}

main

新增

package main

import (
	"ShopBefore/gorm/model"
	"fmt"
	"gorm.io/driver/mysql"
	"gorm.io/gorm"
	"gorm.io/gorm/logger"
	"log"
	"os"
	"time"
)

func main() {

	// 连接对应的数据库
	dsn := fmt.Sprintf("%s:%s@tcp(%s:%d)/%s?charset=utf8mb4&parseTime=True&loc=Local",
		"root", "root", "192.168.193.128", 3306, "test")
	newLogger := logger.New(
		log.New(os.Stdout, "\r\n", log.LstdFlags), // io writer(日志输出的目标,前缀和日志包含的内容——译者注)
		logger.Config{
			SlowThreshold:             time.Second, // 慢 SQL 阈值
			LogLevel:                  logger.Info, // 日志级别
			IgnoreRecordNotFoundError: true,        // 忽略ErrRecordNotFound(记录未找到)错误
			Colorful:                  true,        // 使用用彩色打印
		},
	)

	db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{
		Logger: newLogger,
	})
	if err != nil {
		panic(err)
	}
	var users []model.User
	user := model.User{
		CreditCards: []*model.CreditCard{
			{
				Number: "123",
			},
			{
				Number: "456",
			},
			{
				Number: "789",
			},
		},
	}
	user1 := model.User{
		CreditCards: []*model.CreditCard{
			{
				Number: "321",
			},
			{
				Number: "654",
			},
			{
				Number: "987",
			},
		},
	}
	users = append(users,user)
	users = append(users,user1)
	db.Save(&users)
}

日志:

INSERT INTO `credit_cards` (`created_at`,`updated_at`,`deleted_at`,`number`,`user_id`) VALUES ('2022-06-20 22:40:07.591','2022-06-20 22:40:07.591',NULL,'123',1),('2022-06-20 22:40:07.591','2022-06-20 22:40:07.591',NULL,'456',1),('2022-06-20 22:40:07.591','2022-06-20 22:40:07.591',NULL,'789',1),('2022-06-20 22:40:07.591','2022-06-20 22:40:07.591',NULL,'321',2),('2022-06-20 22:40:07.591','2022-06-20 22:40:07.591',NULL,'654',2),('2022-06-20 22:40:07.591','2022-06-20 22:40:07.591',NULL,'987',2) ON DUPLICATE KEY UPDATE `user_id`=VALUES(`user_id`)
INSERT INTO `users` (`created_at`,`updated_at`,`deleted_at`) VALUES ('2022-06-20 22:40:07.532','2022-06-20 22:40:07.532',NULL),('2022-06-20 22:40:07.532','2022-06-20 22:40:07.532',NULL) ON DUPLICATE KEY UPDATE `updated_at`='2022-06-20 22:40:07.532',`deleted_at`=VALUES(`deleted_at`)

查询

package main

import (
	"ShopBefore/gorm/model"
	"encoding/json"
	"fmt"
	"gorm.io/driver/mysql"
	"gorm.io/gorm"
	"gorm.io/gorm/logger"
	"log"
	"os"
	"time"
)

func main() {

	// 连接对应的数据库
	dsn := fmt.Sprintf("%s:%s@tcp(%s:%d)/%s?charset=utf8mb4&parseTime=True&loc=Local",
		"root", "root", "192.168.193.128", 3306, "test")
	newLogger := logger.New(
		log.New(os.Stdout, "\r\n", log.LstdFlags), // io writer(日志输出的目标,前缀和日志包含的内容——译者注)
		logger.Config{
			SlowThreshold:             time.Second, // 慢 SQL 阈值
			LogLevel:                  logger.Info, // 日志级别
			IgnoreRecordNotFoundError: true,        // 忽略ErrRecordNotFound(记录未找到)错误
			Colorful:                  true,        // 使用用彩色打印
		},
	)

	db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{
		Logger: newLogger,
	})
	if err != nil {
		panic(err)
	}
	
	var user model.User
	db.Preload("CreditCards").Find(&user,2)
	marshal, _ := json.Marshal(user)
	fmt.Println(string(marshal))
}

日志:

SELECT * FROM `credit_cards` WHERE `credit_cards`.`user_id` = 2 AND `credit_cards`.`deleted_at` IS NULL
SELECT * FROM `users` WHERE `users`.`id` = 2 AND `users`.`deleted_at` IS NULL

结果:

{
    "ID": 2,
    "CreatedAt": "2022-06-20T22:40:07.532+08:00",
    "UpdatedAt": "2022-06-20T22:40:07.532+08:00",
    "DeletedAt": null,
    "CreditCards": [
        {
            "ID": 4,
            "CreatedAt": "2022-06-20T22:40:07.591+08:00",
            "UpdatedAt": "2022-06-20T22:40:07.591+08:00",
            "DeletedAt": null,
            "Number": "321",
            "UserId": 2
        },
        {
            "ID": 5,
            "CreatedAt": "2022-06-20T22:40:07.591+08:00",
            "UpdatedAt": "2022-06-20T22:40:07.591+08:00",
            "DeletedAt": null,
            "Number": "654",
            "UserId": 2
        },
        {
            "ID": 6,
            "CreatedAt": "2022-06-20T22:40:07.591+08:00",
            "UpdatedAt": "2022-06-20T22:40:07.591+08:00",
            "DeletedAt": null,
            "Number": "987",
            "UserId": 2
        }
    ]
}

最后

在这里插入图片描述
官方文档看起来很容易误导,让开发以为一对多的关系就必须要存在外键,但是我们再真实的开发环境下,大多是不会用到数据库中的物理外键的,仅仅只是做一个逻辑关联就够了.官方文档这里说的必须存在外键是我们再model里面必须要指明外键,而不是数据库中一定要有这个外键,
注意: 这种情况我们就不能使用db.AutoMigrate() 来自动创建表了,因为我们再代码中指明外键,如果再使用
db.AutoMigrate() 来创建表,那么gorm是一定会帮我们做一个物理外键的

  大数据 最新文章
实现Kafka至少消费一次
亚马逊云科技:还在苦于ETL?Zero ETL的时代
初探MapReduce
【SpringBoot框架篇】32.基于注解+redis实现
Elasticsearch:如何减少 Elasticsearch 集
Go redis操作
Redis面试题
专题五 Redis高并发场景
基于GBase8s和Calcite的多数据源查询
Redis——底层数据结构原理
上一篇文章      下一篇文章      查看所有文章
加:2022-06-23 00:55:58  更:2022-06-23 00:56:42 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/19 21:53:47-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码