当前位置: 首页 > news >正文

Gorm 数据库表迁移与表模型定义

文章目录

    • 一、Docker快速创建MySQL实例
      • 1.1 创建
      • 1.3 创建数据库
    • 二、AutoMigrate介绍与使用
      • 2.1 AutoMigrate介绍
      • 2.2 AutoMigrate 基本使用
    • 三、模型定义
      • 3.1 模型定义
      • 3.2 快速增删改查
      • 3.3 约定
      • 3.4 gorm.Model
    • 四、表模型主键、表名、列名的约定
      • 4.1 主键(Primary Key)
        • 4.1.1 使用 `ID` 作为主键
        • 4.1.2 复合主键
      • 4.2 表名(Table Name)
        • 4.2.1 TableName
        • 4.2.2 临时指定表名
        • 4.2.3 命名策略
      • 4.3 列名(Column Name)
      • 4.4 时间戳跟踪
        • 4.4.1 CreatedAt
        • 4.4.2 UpdatedAt
        • 4.4.3 DeletedAt
    • 五、模型定义高级选项与标签
      • 5.1 字段级权限控制
      • 5.2 创建/更新时间追踪(纳秒、毫秒、秒、Time)
      • 5.3 嵌入结构体
      • 5.4 结构体标签(tags)
      • 5.5 举个例子

一、Docker快速创建MySQL实例

1.1 创建

因为这里我们是测试学习使用,单独安装MySQL 比较费时费力,所以这里使用Docker方便快速掌握Gorm 相关知识。

如果你没有docker环境,可以参考:【一文搞定】Linux、Mac、Windows安装Docker与配置教程!

下载镜像:

docker pull mysql

运行MySQL容器:

docker run -p 3306:3306 --name mysql -v $PWD/conf/my.cnf:/etc/mysql/my.cnf -v $PWD/logs:/logs -v $PWD/data:/mysql_data -e MYSQL_ROOT_PASSWORD=123456 -d mysql

下面是对命令中参数的解释:

  • -p 3306:3306:将容器的 3306 端口映射到主机的 3306 端口

  • -v $PWD/conf/my.cnf:/etc/mysql/my.cnf:将主机当前目录下的 conf/my.cnf 挂载到容器的 /etc/mysql/my.cnf

  • -v $PWD/logs:/logs:将主机当前目录下的 logs 目录挂载到容器的 /logs

  • -v $PWD/data:/mysql_data:将主机当前目录下的 data 目录挂载到容器的 /mysql_data

  • -e MYSQL_ROOT_PASSWORD=123456:初始化 root 用户的密码

查看运行中的容器:

docker ps  

1.3 创建数据库

首先,使用Datagrip 链接数据,接着在使用GORM前手动创建数据库db1,执行如下SQL:

CREATE DATABASE db1;

二、AutoMigrate介绍与使用

2.1 AutoMigrate介绍

AutoMigrate 是 Gorm 提供的一个功能强大的数据库迁移工具,它可以自动创建或更新数据库表结构,使数据库的结构与 Golang 模型一致。使用 AutoMigrate 可以方便地进行数据库表的初始化和更新,而无需手动执行 SQL 语句。

2.2 AutoMigrate 基本使用

在 Gorm 中,你可以通过调用 db.AutoMigrate 方法来进行数据库表的自动迁移。以下是一个基本的使用示例:

package mainimport ("gorm.io/driver/mysql""gorm.io/gorm""gorm.io/gorm/logger""log""os""time"
)type Product struct {gorm.ModelCode  stringPrice uint
}func main() {// 日志配置newLogger := logger.New(log.New(os.Stdout, "\r\n", log.LstdFlags), // io writer(日志输出的目标,前缀和日志包含的内容——译者注)logger.Config{SlowThreshold:             time.Second, // 慢 SQL 阈值LogLevel:                  logger.Info, // 日志级别为infoIgnoreRecordNotFoundError: true,        // 忽略ErrRecordNotFound(记录未找到)错误Colorful:                  true,        // 彩色打印},)dsn := "root:123456@tcp(127.0.0.1:3306)/db1?charset=utf8mb4&parseTime=True&loc=Local"db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{Logger: newLogger,})if err != nil {panic(err) // 如果数据库不存在会报错}db.AutoMigrate(&Product{}) // 可以加多个log.Println("Auto Migration Completed")
}

三、模型定义

3.1 模型定义

模型是标准的 struct,由 Go 的基本数据类型、实现了 Scanner 和 Valuer 接口的自定义类型及其指针或别名组成

例如:

type User struct {ID           uintName         stringEmail        *stringAge          uint8Birthday     *time.TimeMemberNumber sql.NullStringActivatedAt  sql.NullTimeCreatedAt    time.TimeUpdatedAt    time.Time
}

3.2 快速增删改查

package mainimport ("fmt""gorm.io/driver/mysql""gorm.io/gorm""gorm.io/gorm/logger""log""os""time"
)// UserInfo 用户信息
type UserInfo struct {ID     uintName   stringGender stringHobby  string
}func main() {// 日志配置newLogger := logger.New(log.New(os.Stdout, "\r\n", log.LstdFlags), // io writer(日志输出的目标,前缀和日志包含的内容——译者注)logger.Config{SlowThreshold:             time.Second, // 慢 SQL 阈值LogLevel:                  logger.Info, // 日志级别为infoIgnoreRecordNotFoundError: true,        // 忽略ErrRecordNotFound(记录未找到)错误Colorful:                  true,        // 彩色打印},)dsn := "root:123456@tcp(127.0.0.1:3306)/db1?charset=utf8mb4&parseTime=True&loc=Local"db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{Logger: newLogger,})if err != nil {panic(err) // 如果数据库不存在会报错}// 自动迁移db.AutoMigrate(&UserInfo{})u1 := UserInfo{1, "贾维斯", "男", "篮球"}u2 := UserInfo{2, "荆轲", "女", "足球"}// 创建记录db.Create(&u1)db.Create(&u2)// 查询var u = new(UserInfo)db.First(u)fmt.Printf("%#v\n", u)var uu UserInfodb.Find(&uu, "hobby=?", "足球")fmt.Printf("%#v\n", uu)// 更新db.Model(&u).Update("hobby", "双色球")// 删除db.Delete(&u)
}

3.3 约定

GORM 倾向于约定优于配置 默认情况下,GORM 使用 ID 作为主键,使用结构体名的 蛇形复数 作为表名,字段名的 蛇形 作为列名,并使用 CreatedAtUpdatedAt 字段追踪创建、更新时间

如果您遵循 GORM 的约定,您就可以少写的配置、代码。 如果约定不符合您的实际要求,GORM 允许你配置它们

3.4 gorm.Model

GORM 定义一个 gorm.Model 结构体,其包括字段 IDCreatedAtUpdatedAtDeletedAt

// gorm.Model 的定义
type Model struct {ID        uint           `gorm:"primaryKey"`CreatedAt time.TimeUpdatedAt time.TimeDeletedAt gorm.DeletedAt `gorm:"index"`
}

您可以将它嵌入到您的结构体中,以包含这几个字段,详情请参考 嵌入结构体

四、表模型主键、表名、列名的约定

4.1 主键(Primary Key)

4.1.1 使用 ID 作为主键

默认情况下,GORM 会使用 ID 作为表的主键。

type User struct {ID   string // 默认情况下,名为 `ID` 的字段会作为表的主键Name string
}

你可以通过标签 primaryKey 将其它字段设为主键

// 将 `UUID` 设为主键
type Animal struct {ID     int64UUID   string `gorm:"primaryKey"`Name   stringAge    int64
}
4.1.2 复合主键

通过将多个字段设为主键,以创建复合主键,例如:

type Product struct {ID           string `gorm:"primaryKey"`LanguageCode string `gorm:"primaryKey"`Code         stringName         string
}

**注意:**默认情况下,整型 PrioritizedPrimaryField 启用了 AutoIncrement,要禁用它,您需要为整型字段关闭 autoIncrement

type Product struct {CategoryID uint64 `gorm:"primaryKey;autoIncrement:false"`TypeID     uint64 `gorm:"primaryKey;autoIncrement:false"`
}

4.2 表名(Table Name)

GORM 使用结构体名的 蛇形命名 作为表名。对于结构体 User,根据约定,其表名为 users

4.2.1 TableName

您可以实现 Tabler 接口来更改默认表名,例如:

type Tabler interface {TableName() string
}// TableName 会将 User 的表名重写为 `profiles`
func (User) TableName() string {return "profiles"
}

注意: TableName 不支持动态变化,它会被缓存下来以便后续使用。想要使用动态表名,你可以使用 Scopes,例如:

func UserTable(user User) func (tx *gorm.DB) *gorm.DB {return func (tx *gorm.DB) *gorm.DB {if user.Admin {return tx.Table("admin_users")}return tx.Table("users")}
}db.Scopes(UserTable(user)).Create(&user)
4.2.2 临时指定表名

您可以使用 Table 方法临时指定表名,例如:

// 根据 User 的字段创建 `deleted_users` 表
db.Table("deleted_users").AutoMigrate(&User{})// 从另一张表查询数据
var deletedUsers []User
db.Table("deleted_users").Find(&deletedUsers)
// SELECT * FROM deleted_users;db.Table("deleted_users").Where("name = ?", "jinzhu").Delete(&User{})
// DELETE FROM deleted_users WHERE name = 'jinzhu';

查看 from 子查询 了解如何在 FROM 子句中使用子查询

4.2.3 命名策略

GORM 允许用户通过覆盖默认的命名策略更改默认的命名约定,命名策略被用于构建: TableNameColumnNameJoinTableNameRelationshipFKNameCheckerNameIndexName。查看 GORM 配置 获取详情

4.3 列名(Column Name)

根据约定,数据表的列名使用的是 struct 字段名的 蛇形命名

type User struct {ID        uint      // 列名是 `id`Name      string    // 列名是 `name`Birthday  time.Time // 列名是 `birthday`CreatedAt time.Time // 列名是 `created_at`
}

您可以使用 column 标签或 命名策略 来覆盖列名

type Animal struct {AnimalID int64     `gorm:"column:beast_id"`         // 将列名设为 `beast_id`Birthday time.Time `gorm:"column:day_of_the_beast"` // 将列名设为 `day_of_the_beast`Age      int64     `gorm:"column:age_of_the_beast"` // 将列名设为 `age_of_the_beast`
}

4.4 时间戳跟踪

4.4.1 CreatedAt

对于有 CreatedAt 字段的模型,创建记录时,如果该字段值为零值,则将该字段的值设为当前时间

db.Create(&user) // 将 `CreatedAt` 设为当前时间user2 := User{Name: "jinzhu", CreatedAt: time.Now()}
db.Create(&user2) // user2 的 `CreatedAt` 不会被修改// 想要修改该值,您可以使用 `Update`
db.Model(&user).Update("CreatedAt", time.Now())

你可以通过将 autoCreateTime 标签置为 false 来禁用时间戳追踪,例如:

type User struct {CreatedAt time.Time `gorm:"autoCreateTime:false"`
}
4.4.2 UpdatedAt

对于有 UpdatedAt 字段的模型,更新记录时,将该字段的值设为当前时间。创建记录时,如果该字段值为零值,则将该字段的值设为当前时间

db.Save(&user) // 将 `UpdatedAt` 设为当前时间db.Model(&user).Update("name", "jinzhu") // 会将 `UpdatedAt` 设为当前时间db.Model(&user).UpdateColumn("name", "jinzhu") // `UpdatedAt` 不会被修改user2 := User{Name: "jinzhu", UpdatedAt: time.Now()}
db.Create(&user2) // 创建记录时,user2 的 `UpdatedAt` 不会被修改user3 := User{Name: "jinzhu", UpdatedAt: time.Now()}
db.Save(&user3) // 更新时,user3 的 `UpdatedAt` 会修改为当前时间

你可以通过将 autoUpdateTime 标签置为 false 来禁用时间戳追踪,例如:

type User struct {UpdatedAt time.Time `gorm:"autoUpdateTime:false"`
}
4.4.3 DeletedAt
// 只要使用了gorm.Model结构体继承,DeletedAt DeletedAt `gorm:"index"`  字段
// 执行删除是其实是update语句,并没有真正的删除

五、模型定义高级选项与标签

5.1 字段级权限控制

可导出的字段在使用 GORM 进行 CRUD 时拥有全部的权限,此外,GORM 允许您用标签控制字段级别的权限。这样您就可以让一个字段的权限是只读、只写、只创建、只更新或者被忽略

注意: 使用 GORM Migrator 创建表时,不会创建被忽略的字段

type User struct {Name string `gorm:"<-:create"` // allow read and createName string `gorm:"<-:update"` // allow read and updateName string `gorm:"<-"`        // allow read and write (create and update)Name string `gorm:"<-:false"`  // allow read, disable write permissionName string `gorm:"->"`        // readonly (disable write permission unless it configured)Name string `gorm:"->;<-:create"` // allow read and createName string `gorm:"->:false;<-:create"` // createonly (disabled read from db)Name string `gorm:"-"`            // ignore this field when write and read with structName string `gorm:"-:all"`        // ignore this field when write, read and migrate with structName string `gorm:"-:migration"`  // ignore this field when migrate with struct
}

5.2 创建/更新时间追踪(纳秒、毫秒、秒、Time)

GORM 约定使用 CreatedAtUpdatedAt 追踪创建/更新时间。如果您定义了这种字段,GORM 在创建、更新时会自动填充 当前时间

要使用不同名称的字段,您可以配置 autoCreateTimeautoUpdateTime 标签

如果您想要保存 UNIX(毫/纳)秒时间戳,而不是 time,您只需简单地将 time.Time 修改为 int 即可

type User struct {CreatedAt time.Time // 在创建时,如果该字段值为零值,则使用当前时间填充UpdatedAt int       // 在创建时该字段值为零值或者在更新时,使用当前时间戳秒数填充Updated   int64 `gorm:"autoUpdateTime:nano"` // 使用时间戳填纳秒数充更新时间Updated   int64 `gorm:"autoUpdateTime:milli"` // 使用时间戳毫秒数填充更新时间Created   int64 `gorm:"autoCreateTime"`      // 使用时间戳秒数填充创建时间
}

5.3 嵌入结构体

对于匿名字段,GORM 会将其字段包含在父结构体中,例如:

type User struct {gorm.ModelName string
}
// 等效于
type User struct {ID        uint           `gorm:"primaryKey"`CreatedAt time.TimeUpdatedAt time.TimeDeletedAt gorm.DeletedAt `gorm:"index"`Name string
}

对于正常的结构体字段,你也可以通过标签 embedded 将其嵌入,例如:

type Author struct {Name  stringEmail string
}type Blog struct {ID      intAuthor  Author `gorm:"embedded"`Upvotes int32
}
// 等效于
type Blog struct {ID    int64Name  stringEmail stringUpvotes  int32
}

并且,您可以使用标签 embeddedPrefix 来为 db 中的字段名添加前缀,例如:

type Blog struct {ID      intAuthor  Author `gorm:"embedded;embeddedPrefix:author_"`Upvotes int32
}
// 等效于
type Blog struct {ID          int64AuthorName  stringAuthorEmail stringUpvotes     int32
}

5.4 结构体标签(tags)

声明 model 时,tag 是可选的,GORM 支持以下 tag: tag 名大小写不敏感,但建议使用 camelCase 风格,Gorm支持以下标记:

标签名说明
column指定 db 列名
type列数据类型,推荐使用兼容性好的通用类型,例如:所有数据库都支持 bool、int、uint、float、string、time、bytes 并且可以和其他标签一起使用,例如:not nullsize, autoIncrement… 像 varbinary(8) 这样指定数据库数据类型也是支持的。在使用指定数据库数据类型时,它需要是完整的数据库数据类型,如:MEDIUMINT UNSIGNED not NULL AUTO_INCREMENT
serializer指定如何将数据序列化和反序列化到数据库中的序列化程序,如: serializer:json/gob/unixtime
size指定列数据大小/长度, 如: size:256
primaryKey指定列作为主键
unique指定列作为unique
default指定列的默认值
precision指定列的精度
scale指定列的比例
not null指定列不为空
autoIncrement指定列自增
autoIncrementIncrement自动递增步长,控制连续列值之间的间隔
embedded嵌入字段
embeddedPrefix嵌入嵌入字段的字段列名前缀
autoCreateTime跟踪当前时间创建时,对于’int’字段,它将跟踪unix秒,使用值’nano/'milli跟踪unix nano/milli秒,如: autoCreateTime:nano
autoUpdateTime在创建/更新时跟踪当前时间,对于’int’字段,它将跟踪unix秒,使用值’nano/'milli跟踪unix nano/milli秒, 如: autoUpdateTime:milli
index使用选项创建索引,对多个字段使用相同的名称创建复合索引, 详情参照 Indexes
uniqueIndex与’index’相同,但创建唯一索引
check创建检查约束, 如: check:age > 13, 参照 Constraints
<-设置字段的写入权限, <-:create 仅创建字段, <-:update 仅更新字段, <-:false 没有写权限, <- 创建和更新权限
->设置字段读权限, ->:false 没有读权限
-忽略该字段, - 没有读写权限, -:migration 没有迁移权限, -:all 没有 read/write/migrate 权限
comment迁移时为字段添加注释

5.5 举个例子

package mainimport ("gorm.io/driver/mysql""gorm.io/gorm""gorm.io/gorm/logger""log""os""time"
)// Teacher 定义一个模型
type Teacher struct {UserId uint   `gorm:"primaryKey"`                           // 设置主键Name   string `gorm:"column:teacher_name;type:varchar(60)"` // 设置字段名和类型Gender uint   `gorm:"index"`                                // 设置索引
}func main() {// 日志配置newLogger := logger.New(log.New(os.Stdout, "\r\n", log.LstdFlags), // io writer(日志输出的目标,前缀和日志包含的内容——译者注)logger.Config{SlowThreshold:             time.Second, // 慢 SQL 阈值LogLevel:                  logger.Info, // 日志级别为infoIgnoreRecordNotFoundError: true,        // 忽略ErrRecordNotFound(记录未找到)错误Colorful:                  true,        // 彩色打印},)dsn := "root:123456@tcp(127.0.0.1:3306)/db1?charset=utf8mb4&parseTime=True&loc=Local"db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{Logger: newLogger,})if err != nil {panic(err) // 如果数据库不存在会报错}db.AutoMigrate(&Teacher{})// 如果表之前存在会修改,但是只会修改之前存在的字段,有问题// 改了字段属性,再执行AutoMigrate,字段属性会变,设置default测试看
}

相关文章:

Gorm 数据库表迁移与表模型定义

文章目录 一、Docker快速创建MySQL实例1.1 创建1.3 创建数据库 二、AutoMigrate介绍与使用2.1 AutoMigrate介绍2.2 AutoMigrate 基本使用 三、模型定义3.1 模型定义3.2 快速增删改查3.3 约定3.4 gorm.Model 四、表模型主键、表名、列名的约定4.1 主键&#xff08;Primary Key&a…...

系列三、Spring Security中自定义用户名/密码

一、Spring Security中自定义用户名/密码 1.1、自定义用户名/密码 1.1.1、配置文件中配置 spring.security.user.nameroot spring.security.user.password123456 1.1.2、定义基于内存的用户 /*** Author : 一叶浮萍归大海* Date: 2024/1/11 21:50* Description:*/ Configu…...

如何顺滑使用华为云编译构建平台?

这两年平台构建服务需求越来越大&#xff0c;却一直苦于找不到一些指南&#xff0c; 这里特意写了一篇&#xff0c; 对在学习代码阶段和新手程序员朋友也蛮友好&#xff0c; 配置真的也不难&#xff0c; 也特别适合想尝试从0到1做个APP的朋友了。 以华为云的CodeArts Build为例…...

查看Linux磁盘空间

(1)、该命令会列出当前系统所有挂载的文件系统以及它们的使用情况&#xff0c;包括总容量、已用空间、可用空间、使用百分比等信息 df -h如果查看某一个文件夹的,可以 df -h folderName (2)、计算指定目录下所有文件和子目录所占用的磁盘空间大小&#xff0c;并以人类可读的格…...

2023年全国职业院校技能大赛(高职组)“云计算应用”赛项赛卷⑩

2023年全国职业院校技能大赛&#xff08;高职组&#xff09; “云计算应用”赛项赛卷10 目录 需要竞赛软件包环境以及备赛资源可私信博主&#xff01;&#xff01;&#xff01; 2023年全国职业院校技能大赛&#xff08;高职组&#xff09; “云计算应用”赛项赛卷10 模块…...

vim基本操作命令

一、vi简介 vi是“Visual interface”的简称&#xff0c;它在Linux上的地位就仿佛Edit程序在DOS上一样。它可以执行输出、删除、查找、替换、块操作等众多文本操作&#xff0c;而且用户可以根据自己的需要对其进行定制。Vi不是一个排版程序&#xff0c;它不象Word或WPS那样可以…...

mybatis-plus实现真正的批量插入

1、安装依赖 <dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-extension</artifactId><version>3.5.3.2</version></dependency>版本与mybatis-plus一致 2、编写sql注入器 package com.example.answe…...

pytorch12:GPU加速模型训练

目录 1、CPU与GPU2、数据迁移至GPU2.1 to函数使用方法 3、torch.cuda常用方法4、多GPU并行运算4.1 torch.nn.DataParallel4.2 torch.distributed加速并行训练 5、gpu总结 1、CPU与GPU CPU&#xff08;Central Processing Unit, 中央处理器&#xff09;&#xff1a;主要包括控制…...

P1603 斯诺登的密码题解

题目 &#xff08;1&#xff09;找出句子中所有用英文表示的数字(≤20)&#xff0c;列举在下&#xff1a; 正规&#xff1a;one two three four five six seven eight nine ten eleven twelve thirteen fourteen fifteen sixteen seventeen eighteen nineteen twenty 非正规…...

YOLOv8 + openVINO 多线程数据读写顺序处理

多线程数据读写顺序处理 一个典型的生产者-消费者模型&#xff0c;在这个模型中&#xff0c;多个工作线程并行处理从共享队列中获取的数据&#xff0c;并将处理结果以保持原始顺序的方式放入另一个队列。 多线程处理模型&#xff0c;具体细节如下&#xff1a; 1.数据:数据里必…...

端到端自动驾驶

自动驾驶主要流程&#xff1a;感知->预测->规划 预测是预测周围目标&#xff08;车、行人、动物等&#xff09;的轨迹&#xff0c;规划是规划自车的运动轨迹。 UniAD[CVPR 2023]: 使用transformer架构&#xff0c;统一自动驾驶流程&#xff0c;完成所有检测&#xff0c…...

Developer Tools for Game Creator 1

插件包含: 持久世界时间管理系统 单击以生成对象或预设 游戏内调试控制台 游戏内事件控制台 控制台管理控制 命令模板脚本 游戏内屏幕截图 低分辨率和高分辨率图像 缩略图生成 移动支持 使用Game Creator Action或拖放来激活和控制组件,无需编码。 通过此资产,您可以获得: …...

软件测试|好用的pycharm插件推荐(三)——Rainbow Brackets

简介 我们平时写代码的时候&#xff0c;括号是让我们非常头疼的地方&#xff0c;特别是代码逻辑很多&#xff0c;层层嵌套的情况。 一眼很难看出&#xff0c;代码是从哪个括号开始&#xff0c;到哪个反括号结束的。这个时候要是有一款工具能够让我们一眼就看出代码从哪个括号开…...

MyBatisPlus学习二:常用注解、条件构造器、自定义sql

常用注解 基本约定 MybatisPlus通过扫描实体类&#xff0c;并基于反射获取实体类信息作为数据库表信息。可以理解为在继承BaseMapper 要指定对应的泛型 public interface UserMapper extends BaseMapper<User> 实体类中&#xff0c;类名驼峰转下划线作为表名、名为id的…...

深入理解C#中的引用类型、引用赋值以及 `ref` 关键字

深入理解C#中的引用类型、引用赋值以及 ref 关键字 在C#编程中&#xff0c;理解引用类型、引用赋值以及 ref 关键字的使用对于编写高效、可靠的代码至关重要。本文将深入探讨这些概念&#xff0c;帮助您更好地理解C#的工作原理。 引用类型简介 在C#中&#xff0c;所有的类型都…...

【算法提升】LeetCode每五日一总结【01/01--01/05】

文章目录 LeetCode每五日一总结【01/01--01/05】2023/12/31今日数据结构&#xff1a;二叉树的前/中/后 序遍历<非递归> 2024/01/01今日数据结构&#xff1a;二叉树的 前/中/后 序遍历 三合一代码<非递归>今日数据结构&#xff1a;二叉树的 前/中/后 序遍历 三合一代…...

linux下驱动学习—平台总线 (3)

platform 设备驱动 在设备驱动模型中&#xff0c; 引入总线的概念可以对驱动代码和设备信息进行分离。但是驱动中总线的概念是软件层面的一种抽象&#xff0c;与我们SOC中物理总线的概念并不严格相等&#xff1a; 物理总线&#xff1a;芯片与各个功能外设之间传送信息的公共通…...

【leetcode】字符串中的第一个唯一字符

题目描述 给定一个字符串 s &#xff0c;找到 它的第一个不重复的字符&#xff0c;并返回它的索引 。如果不存在&#xff0c;则返回 -1 。 用例 示例 1&#xff1a; 输入: s “leetcode” 输出: 0 示例 2: 输入: s “loveleetcode” 输出: 2 示例 3: 输入: s “aabb”…...

Serverless与Kubernetes(K8s)的区别、优缺点及应用场景

Serverless与Kubernetes&#xff08;K8s&#xff09;的区别 架构模型 Serverless是一种基于事件驱动的计算模型&#xff0c;它允许开发者编写应用程序时无需关心底层的基础设施。在Serverless架构中&#xff0c;云服务提供商会负责管理服务器、操作系统、运行时环境等基础设施&…...

参数小,性能强!开源多模态模型—TinyGPT-V

安徽工程大学、南洋理工大学和理海大学的研究人员开源了多模态大模型——TinyGPT-V。 TinyGPT-V以微软开源的Phi-2作为基础大语言模型&#xff0c;同时使用了视觉模型EVA实现多模态能力。尽管TinyGPT-V只有28亿参数&#xff0c;但其性能可以媲美上百亿参数的模型。 此外&…...

Chapter03-Authentication vulnerabilities

文章目录 1. 身份验证简介1.1 What is authentication1.2 difference between authentication and authorization1.3 身份验证机制失效的原因1.4 身份验证机制失效的影响 2. 基于登录功能的漏洞2.1 密码爆破2.2 用户名枚举2.3 有缺陷的暴力破解防护2.3.1 如果用户登录尝试失败次…...

java_网络服务相关_gateway_nacos_feign区别联系

1. spring-cloud-starter-gateway 作用&#xff1a;作为微服务架构的网关&#xff0c;统一入口&#xff0c;处理所有外部请求。 核心能力&#xff1a; 路由转发&#xff08;基于路径、服务名等&#xff09;过滤器&#xff08;鉴权、限流、日志、Header 处理&#xff09;支持负…...

鸿蒙中用HarmonyOS SDK应用服务 HarmonyOS5开发一个医院挂号小程序

一、开发准备 ​​环境搭建​​&#xff1a; 安装DevEco Studio 3.0或更高版本配置HarmonyOS SDK申请开发者账号 ​​项目创建​​&#xff1a; File > New > Create Project > Application (选择"Empty Ability") 二、核心功能实现 1. 医院科室展示 /…...

【ROS】Nav2源码之nav2_behavior_tree-行为树节点列表

1、行为树节点分类 在 Nav2(Navigation2)的行为树框架中,行为树节点插件按照功能分为 Action(动作节点)、Condition(条件节点)、Control(控制节点) 和 Decorator(装饰节点) 四类。 1.1 动作节点 Action 执行具体的机器人操作或任务,直接与硬件、传感器或外部系统…...

聊一聊接口测试的意义有哪些?

目录 一、隔离性 & 早期测试 二、保障系统集成质量 三、验证业务逻辑的核心层 四、提升测试效率与覆盖度 五、系统稳定性的守护者 六、驱动团队协作与契约管理 七、性能与扩展性的前置评估 八、持续交付的核心支撑 接口测试的意义可以从四个维度展开&#xff0c;首…...

Python 包管理器 uv 介绍

Python 包管理器 uv 全面介绍 uv 是由 Astral&#xff08;热门工具 Ruff 的开发者&#xff09;推出的下一代高性能 Python 包管理器和构建工具&#xff0c;用 Rust 编写。它旨在解决传统工具&#xff08;如 pip、virtualenv、pip-tools&#xff09;的性能瓶颈&#xff0c;同时…...

【VLNs篇】07:NavRL—在动态环境中学习安全飞行

项目内容论文标题NavRL: 在动态环境中学习安全飞行 (NavRL: Learning Safe Flight in Dynamic Environments)核心问题解决无人机在包含静态和动态障碍物的复杂环境中进行安全、高效自主导航的挑战&#xff0c;克服传统方法和现有强化学习方法的局限性。核心算法基于近端策略优化…...

云原生安全实战:API网关Kong的鉴权与限流详解

&#x1f525;「炎码工坊」技术弹药已装填&#xff01; 点击关注 → 解锁工业级干货【工具实测|项目避坑|源码燃烧指南】 一、基础概念 1. API网关&#xff08;API Gateway&#xff09; API网关是微服务架构中的核心组件&#xff0c;负责统一管理所有API的流量入口。它像一座…...

「全栈技术解析」推客小程序系统开发:从架构设计到裂变增长的完整解决方案

在移动互联网营销竞争白热化的当下&#xff0c;推客小程序系统凭借其裂变传播、精准营销等特性&#xff0c;成为企业抢占市场的利器。本文将深度解析推客小程序系统开发的核心技术与实现路径&#xff0c;助力开发者打造具有市场竞争力的营销工具。​ 一、系统核心功能架构&…...

深度学习之模型压缩三驾马车:模型剪枝、模型量化、知识蒸馏

一、引言 在深度学习中&#xff0c;我们训练出的神经网络往往非常庞大&#xff08;比如像 ResNet、YOLOv8、Vision Transformer&#xff09;&#xff0c;虽然精度很高&#xff0c;但“太重”了&#xff0c;运行起来很慢&#xff0c;占用内存大&#xff0c;不适合部署到手机、摄…...