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

gorm框架

连接

需要下载mysql的驱动

go get gorm.io/driver/mysql
go get gorm.io/gorm

约定

  1. 主键:GORM 使用一个名为ID 的字段作为每个模型的默认主键。
  2. 表名:默认情况下,GORM 将结构体名称转换为 snake_case 并为表名加上复数形式。 例如,一个 User 结构体在数据库中的表名变为 users 。
  3. 列名:GORM 自动将结构体字段名称转换为 snake_case 作为数据库中的列名。
  4. 时间戳字段:GORM使用字段 CreatedAt 和 UpdatedAt 来自动跟踪记录的创建和更新时间。

简单连接

username := "root"  //账号
password := "325523"  //密码
host := "127.0.0.1" //数据库地址,可以是Ip或者域名
port := 3306        //数据库端口
Dbname := "gorm"   //数据库名
timeout := "10s"    //连接超时,10秒// root:325523@tcp(127.0.0.1:3306)/gorm?
dsn := fmt.Sprintf("%s:%s@tcp(%s:%d)/%s?charset=utf8mb4&parseTime=True&loc=Local&timeout=%s", username, password, host, port, Dbname, timeout)//连接MYSQL, 获得DB类型实例,用于后面的数据库读写操作。
db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{//SkipDefaultTransaction: true, //设置跳过默认事务NamingStrategy: schema.NamingStrategy{TablePrefix:   "f_", //表名前缀SingularTable: true, //是否单数表名NoLowerCase:   true, //是否不要小写转换},
})if err != nil {panic("连接数据库失败, error=" + err.Error())
}
//连接成功
//gorm.DB是GORM库中的一个结构体,用于表示数据库连接,可以在整个程序中访问和操作数据库
fmt.Println(db)

高级配置

跳过默认事务

为了确保数据一致性,GORM 会在事务里执行写入操作(创建、更新、删除)。如果没有这方面的要求,您可以在初始化时禁用它,这样可以获得60%的性能提升

db, err := gorm.Open(mysql.Open("gorm.db"), &gorm.Config{SkipDefaultTransaction: true,
})

命名策略

gorm采用的命名策略是,表名是蛇形复数,字段名是蛇形单数(蛇形命名:单词之间采用下划线分割,单词全小写)

type Student struct {Name      stringAge       intMyStudent string
}

gorm会为我们这样生成表结构

CREATE TABLE `students` (`name` longtext,`age` bigint,`my_student` longtext)

我们也可以修改这些策略

db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{NamingStrategy: schema.NamingStrategy{TablePrefix:   "f_",  // 表名前缀SingularTable: false, // 关闭单数表名NoLowerCase:   false, // 是否不要小写转换(false代表否,表示要小写转换,将大写转换为小写)},
})//生成的表
CREATE TABLE `f_students` (`Name` longtext,`Age` bigint,`MyStudent` longtext)

显示日志

gorm的默认日志是只打印错误和慢SQL

可以自己设置

var mysqlLogger logger.Interface
// 要显示的日志等级
mysqlLogger = logger.Default.LogMode(logger.Info)
db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{Logger: mysqlLogger,
})

如果你想自定义日志的显示

那么可以使用如下代码

newLogger := logger.New(log.New(os.Stdout, "\r\n", log.LstdFlags), // (日志输出的目标,前缀和日志包含的内容)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,
})

部分展示日志

var student Student
session := DB.Session(&gorm.Session{Logger: newLogger,
})
session.First(&student)
// SELECT * FROM `students` ORDER BY `students`.`name` LIMIT 1

如果只想某些语句显示日志

DB.Debug().First(&model)

模型定义

在GORM中模型(Models)通常是正常定义的结构体、基本的go类型或它们的指针。 同时也支持sql.Scanner及driver.Valuer接口(interfaces)。

gorm.Model

为了方便模型定义,GORM内置了一个gorm.Model结构体。gorm.Model是一个包含了ID, CreatedAt, UpdatedAt, DeletedAt四个字段的Golang结构体。

// gorm.Model 定义(go语言内置)
type Model struct {ID        uint `gorm:"primary_key"`CreatedAt time.Time // 初次创建记录的时间UpdatedAt time.Time // 每次更新记录的时间DeletedAt *time.Time // 删除该记录的时间
}
  • ID :每个记录的唯一标识符(主键)。
  • CreatedAt :在创建记录时自动设置为当前时间。
  • UpdatedAt:每当记录更新时,自动更新为当前时间。
  • DeletedAt:用于软删除(将记录标记为已删除,而实际上并未从数据库中删除)。

你可以将它嵌入到你自己的结构体模型中:

// 将 `ID`, `CreatedAt`, `UpdatedAt`, `DeletedAt`字段注入到`User`模型中
type User struct {gorm.ModelName string
}

模型定义示例

type User struct {gorm.Model   Name         stringAge          sql.NullInt64Birthday     *time.TimeEmail        string  `gorm:"type:varchar(100);unique_index"`Role         string  `gorm:"size:255"` // 设置字段大小为255MemberNumber *string `gorm:"unique;not null"` // 设置会员号(member number)唯一并且不为空Num          int     `gorm:"AUTO_INCREMENT"` // 设置 num 为自增类型Address      string  `gorm:"index:addr"` // 给address字段创建名为addr的索引IgnoreMe     int     `gorm:"-"` // 忽略本字段
}

结构体标记(tags)

使用结构体声明模型时,标记(tags)是可选项。gorm支持以下标记:

支持的结构体标记(Struct tags)

Column

指定列名

Type

指定列数据类型

Size

指定列大小, 默认值255

PRIMARY_KEY

将列指定为主键

UNIQUE

将列指定为唯一

DEFAULT

指定列默认值

PRECISION

指定列精度

NOT NULL

将列指定为非 NULL

AUTO_INCREMENT

指定列是否为自增类型

INDEX

创建具有或不带名称的索引, 如果多个索引同名则创建复合索引

UNIQUE_INDEX

和INDEX

类似,只不过创建的是唯一索引

EMBEDDED

将结构设置为嵌入

EMBEDDED_PREFIX

设置嵌入结构的前缀

-

忽略此字段

关联相关标记(tags)

MANY2MANY

指定连接表

FOREIGNKEY

设置外键

ASSOCIATION_FOREIGNKEY

设置关联外键

POLYMORPHIC

指定多态类型

POLYMORPHIC_VALUE

指定多态值

JOINTABLE_FOREIGNKEY

指定连接表的外键

ASSOCIATION_JOINTABLE_FOREIGNKEY

指定连接表的关联外键

SAVE_ASSOCIATIONS

是否自动完成 save 的相关操作

ASSOCIATION_AUTOUPDATE

是否自动完成 update 的相关操作

ASSOCIATION_AUTOCREATE

是否自动完成 create 的相关操作

ASSOCIATION_SAVE_REFERENCE

是否自动完成引用的 save 的相关操作

PRELOAD

是否自动完成预加载的相关操作

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

定义一张表

type Student struct {ID    uint // gorm会默认使用ID字段作为主键Name  stringEmail *string // 使用指针是为了存空值
}

小写属性是不会生成字段的

自动生成表结构

// 可以放多个
DB.AutoMigrate(&Student{})

AutoMigrate的逻辑是只新增,不删除,不修改(类型不修改,大小会修改)

例如将字段名Name修改为Name1,进行迁移,会多出一个name1的字段(原本name字段不会被删除)

AutoMigrate 方法的核心逻辑如下:

  • 新增字段:如果模型中添加了新的字段,AutoMigrate 会在数据库表中相应地新增这些字段。
  • 不删除字段:如果模型中删除了某个字段,AutoMigrate 不会删除数据库中的这个字段。这样可以避免数据丢失。
  • 不修改字段类型:虽然可以通过 AutoMigrate 来调整字段的大小或其他属性,但一般来说,字段的类型是不被修改的。如果需要修改字段类型,通常需要手动执行相应的 SQL 语句

修改大小

我们可以使用gorm的标签进行修改

有两种方式

Name  string  `gorm:"type:varchar(12)"`
Name  string  `gorm:"size:2"`

字段标签

type 定义字段类型

size 定义字段大小

column 自定义列名

primaryKey 将列定义为主键

unique 将列定义为唯一键

default 定义列的默认值

not null 不可为空

embedded 嵌套字段

embeddedPrefix 嵌套字段前缀

comment 注释

多个标签之前用 ; 连接

type StudentInfo struct {Email  *string `gorm:"size:32"` // 使用指针是为了存空值Addr   string  `gorm:"column:y_addr;size:16"`Gender bool    `gorm:"default:true"`
}
type Student struct {Name string      `gorm:"type:varchar(12);not null;comment:用户名"`UUID string      `gorm:"primaryKey;unique;comment:主键"`Info StudentInfo `gorm:"embedded;embeddedPrefix:s_"`
}// 建表语句
CREATE TABLE `students` (`name` varchar(12) NOT NULL COMMENT '用户名',`uuid` varchar(191) UNIQUE COMMENT '主键',`s_email` varchar(32),`s_y_addr` varchar(16),`s_gender` boolean DEFAULT true,PRIMARY KEY (`uuid`)
)

单表操作

表结构

type Student struct {ID     uint   `gorm:"size:3"`Name   string `gorm:"size:8"`Age    int    `gorm:"size:3"`Gender boolEmail  *string `gorm:"size:32"` //指针类型,可以传nil值
}

选定/忽略字段

Select选定字段

Omit忽略字段

增加(Create)

忽略零值

单条插入

email := "xxx@qq.com"
// 创建记录
student := Student{Name:   "枫枫",Age:    21,Gender: true,Email:  &email,
}
DB.Create(&student)
fmt.Printf("%#v\n", student)  
// main.Student{ID:0x2, Name:"zhangsan", Age:23, Gender:false, Email:(*string)(0x11d40980)}
// 由于我们传递的是一个指针,调用完Create之后,student这个对象上面就有该记录的信息了,如创建的id

有两个地方需要注意

  1. 指针类型是为了更好的存nil类型,但是传值的时候,也记得传指针
  2. Create接收的是一个指针,而不是值

批量插入

Create方法还可以用于插入多条记录

var studentList []Student
for i := 0; i < 100; i++ {studentList = append(studentList, Student{Name:   fmt.Sprintf("机器人%d号", i+1),Age:    21,Gender: true,Email:  &email,})
}
DB.Create(&studentList)

既可以使用结构体或map来创建,当使用map来创建时,钩子方法不会执行,关联不会被保存且不会回写主键

注意

可以通过 tag 定义字段的默认值,比如:

type User struct {ID   int64Name string `gorm:"default:'小王子'"`Age  int64
}

通过tag定义字段的默认值,在创建记录时候生成的 SQL 语句会排除没有值值为零值的字段。 在将记录插入到数据库后,Gorm会从数据库加载那些字段的默认值。

举个例子:

var user = User{Name: "", Age: 99}
db.Create(&user)

上面代码实际执行的SQL语句是INSERT INTO users("age") values('99');,排除了零值字段Name,而在数据库中这一条数据会使用设置的默认值"小王子"作为Name字段的值。

所有字段的零值都不会保存到数据库内,但会使用他们的默认值。 如果想避免这种情况,可以考虑使用指针或实现 Scanner/Valuer接口,比如:

使用指针方式实现零值存入数据库
// 使用指针
type User struct {ID   int64Name *string `gorm:"default:'小王子'"`Age  int64
}
user := User{Name: new(string), Age: 18))}
db.Create(&user)  // 此时数据库中该条记录name字段的值就是''
使用Scanner/Valuer接口方式实现零值存入数据库
// 使用 Scanner/Valuer
type User struct {ID int64Name sql.NullString `gorm:"default:'小王子'"` // sql.NullString 实现了Scanner/Valuer接口Age  int64
}
user := User{Name: sql.NullString{"", true}, Age:18}
db.Create(&user)  // 此时数据库中该条记录name字段的值就是''

查询

单条查询(Take)

根据顺序查询
var student Student
DB.Take(&student)  //查找表中一条匹配的记录,并将其封装到student中,方法返回一个错误
// SELECT * FROM `students` LIMIT 1DB.First(&student) //查询第一条匹配的数据(主键升序)并将其封装到student中,没有找到时不会返回错误,而是将结果设置为该结构体类型的零值
// SELECT * FROM `students` ORDER BY `students`.`id` LIMIT 1DB.Last(&student)  //查询表中最后一条匹配的数据(主键降序)并将其封装到student中,没有找到时不会返回错误,而是将结果设置为该结构体类型的零值
// SELECT * FROM `students` ORDER BY `students`.`id` DESC LIMIT 1

First 和 Last 方法会按主键排序找到第一条记录和最后一条记录 (分别)。 只有在目标 struct 是指针或者通过 db.Model() 指定 model 时,该方法才有效。如果相关 model 没有定义主键,那么将按 model 的第一个字段进行排序

Model()方法是一个非常重要的函数,它用于指定后续数据库操作所针对的模型(Model)。这个方法通常用于告诉GORM你想要对哪个模型进行操作,特别是在执行更新(Update)、删除(Delete)等操作时,你需要明确指出操作的目标模型。

  • 不影响原始记录:使用Model()方法时,你不需要传入具体的实例,而只需要传入模型的类型。这意味着GORM不会自动加载任何记录,而是根据你提供的模型类型来确定操作的目标。
  • 链式操作:Model()方法返回的是一个*gorm.DB对象,这意味着你可以将它与其他GORM方法链式调用,如Where()、Updates()、Update()、Delete()等。
根据主键查询
var student Student
DB.Take(&student, 2)//查询主键id是2的
fmt.Println(student)student = Student{} // 重新赋值
DB.Take(&student, "4")//查询主键id是"4"(字符串)的
fmt.Println(student)

Take的第二个参数,默认会根据主键查询,可以是字符串,可以是数字

根据其他条件查询

使用?作为占位符,将查询的内容放入?

var student Student
DB.Take(&student, "name = ?", "机器人27号")
fmt.Println(student)SELECT * FROM `students` WHERE name = '机器人27号' LIMIT 1

使用?可以有效的防止sql注入,它的原理就是将参数全部转义,将"机器人27号"识别为字符串,去掉双引号用单引号包围,替换掉?占位符

var student []Student
//不会出现sql注入
DB.Take(&student, "name = ?", "机器人27号' or 1=1;#")
//SELECT * FROM `students` WHERE name = '机器人27号' or 1=1;#' LIMIT 1 //会出现sql注入
DB.Take(&student,fmt.sprintf("name = '%s'","机器人27号' or 1=1;#'))
//SELECT * FROM `students` WHERE name = '机器人27号' or 1=1;#' LIMIT 1 
根据struct查询

会忽略零值

var student Student // 只能有一个主键值 student.ID = 2 //student.Name = "枫枫" DB.Take(&student) fmt.Println(student)

多条查询(Find)

1.使用Find()方法

先将所有符合条件的记录都加载到studentList切片中,再进行更新操作(先查询再更新)。

对单个对象使用Find而不带limit,db.Find(&user)将会查询整个表并且只返回第一个对象。

2.使用Model()方法

直接在数据库层面进行条件筛选和更新,不需要将所有记录加载到内存中。这在处理大量数据时更为高效,因为它只涉及一次数据库操作。

根据顺序查询
var studentList []Student
DB.Find(&studentList)//查询所有数据并将其封装到studentList
for _, student := range studentList {fmt.Println(student)
}// 由于email是指针类型,所以看不到实际的内容
// 但是序列化之后,会转换为我们可以看得懂的方式
var studentList []Student
DB.Find(&studentList)
for _, student := range studentList {data, _ := json.Marshal(student)fmt.Println(string(data))
}
根据主键列表查询
var studentList []Student
DB.Find(&studentList, []int{1, 3, 5, 7})
DB.Find(&studentList, 1, 3, 5, 7)  // 二者效果相同
fmt.Println(studentList)
根据其他条件查询
DB.Find(&studentList, "name in ?", []string{"枫枫", "zhangsan"})

获取结果

1.获取查询的记录数量(受影响的行数)

count := DB.Find(&studentList).RowsAffected

2.是否查询失败,返回错误信息

err := DB.Find(&studentList).Error

查询失败有:查询为空,查询条件错误,sql语法错误

可以使用判断

var student Student
err := DB.Take(&student, "xx").Error
switch err {
case gorm.ErrRecordNotFound:fmt.Println("没有找到")
default:fmt.Println("sql错误")
}

更新

更新的前提的先查询到记录

保存所有字段(更新单条记录)(Save)

  1. 不要将 Save 和 Model一同使用, 这是未定义的行为
  2. 保存是一个组合函数。 如果保存值不包含主键,它将执行 Create,否则它将执行 Update (包含所有字段)。

它会保存所有字段,即使零值也会更新(不会忽略零值)

var student Student
DB.Take(&student)//先查询到记录才能更新
student.Age = 23
// 全字段更新
DB.Save(&student)
// UPDATE `students` SET `name`='枫枫',`age`=23,`gender`=true,`email`='xxx@qq.com' WHERE `id` = 1//零值也会更新
DB.Take(&student)//先查询到记录才能更新
student.Age = 0
// 全字段更新
DB.Save(&student)
// UPDATE `students` SET `name`='枫枫',`age`=0,`gender`=true,`email`='xxx@qq.com' WHERE `id` = 1

可以使用select选择要更新的字段

var student Student
DB.Take(&student)//先查询到记录
student.Name = "xiaoming"
student.Age = 21
// 更新指定字段(只更新age,不更新name),Select中传入表中字段名
DB.Select("age").Save(&student)
// UPDATE `students` SET `age`=21 WHERE `id` = 1

更新多条记录

更新单个字段(Update)

Update()方法

  • 更新单个字段,只接受两个参数:字段名和一个值
  • 忽略零值字段,只更新非零值字段(如果传入的是该字段类型的零值,该字段不会被更新)

给所有年龄21的学生,都更新一下邮箱

var studentList []Student
//以下两种效果一样,效率不同
DB.Find(&studentList, "age = ?", 21).Update("email", "is21@qq.com")
DB.Model(&Student{}).Where("age = ?", 21).Update("email", "is21@qq.com")
// UPDATE `students` SET `email`='is22@qq.com' WHERE age = 21
更新多个字段(Updates)

Updates方法

  • 一次性更新多个字段,接受一个结构体作为参数,包含要更新的字段和它们的新值
  • 忽略零值字段,只更新非零值字段(如果传入的是该字段类型的零值,该字段不会被更新)
email := "xxx@qq.com"
DB.Model(&Student{}).Where("age = ?", 21).Updates(Student{Email:  &email,Gender: false,  // Gender属性设为零值(bool类型),这个不会更新
})
// 只有email属性会被更新
// UPDATE `students` SET `email`='xxx@qq.com' WHERE age = 21

用select选中特定字段可以更新零值

email := "xxx1@qq.com"
//使用Select方法指定要更新的字段,即使是零值也会被更新
DB.Model(&Student{}).Where("age = ?", 21).Select("gender", "email").Updates(Student{Email:  &email,Gender: false, //设置为零值也会被更新
})
// UPDATE `students` SET `gender`=false,`email`='xxx1@qq.com' WHERE age = 21

用map也可以更新零值

DB.Model(&Student{}).Where("age = ?", 21).Updates(map[string]any{"email":  &email,"gender": false, //使用map,即使是零值也会被更新
})

删除(Delete)

删除一条记录

删除一条记录时,删除对象需要指定主键,否则会触发 批量删除,例如:

// email 的 ID 是 `10`
db.Delete(&email)
// DELETE from emails where id = 10;// 带额外条件的删除
db.Where("name = ?", "jinzhu").Delete(&email)
// DELETE from emails where id = 10 AND name = "jinzhu";

根据主键删除

GORM 允许通过主键(可以是复合主键)和内联条件来删除对象

db.Delete(&User{}, 10)
// DELETE FROM users WHERE id = 10;db.Delete(&User{}, "10")
// DELETE FROM users WHERE id = 10;db.Delete(&users, []int{1,2,3})
// DELETE FROM users WHERE id IN (1,2,3)

批量删除

如果指定的值不包括主属性,那么 GORM 会执行批量删除,它将删除所有匹配的记录

db.Where("email LIKE ?", "%jinzhu%").Delete(&Email{})
// DELETE from emails where email LIKE "%jinzhu%";db.Delete(&Email{}, "email LIKE ?", "%jinzhu%")
// DELETE from emails where email LIKE "%jinzhu%";

 Hook钩子函数

对象生命周期

Hook 是在创建、查询、更新、删除等操作之前、之后调用的函数。

如果您已经为模型定义了指定的方法,它会在创建、更新、查询、删除时自动被调用。如果任何回调返回错误,GORM 将停止后续的操作并回滚事务。

钩子方法的函数签名应该是 func(*gorm.DB) error

创建对象

创建时可用的 hook

// 开始事务
BeforeSave
BeforeCreate
// 关联前的 save
// 插入记录至 db
// 关联后的 save
AfterCreate
AfterSave
// 提交或回滚事务

代码示例:

func (u *User) BeforeCreate(tx *gorm.DB) (err error) {u.UUID = uuid.New()if !u.IsValid() {err = errors.New("can't save invalid data")}return
}func (u *User) AfterCreate(tx *gorm.DB) (err error) {if u.ID == 1 {tx.Model(u).Update("role", "admin")}return
}

注意 在 GORM 中保存、删除操作会默认运行在事务上, 因此在事务完成之前该事务中所作的更改是不可见的,如果您的钩子返回了任何错误,则修改将被回滚。

func (u *User) AfterCreate(tx *gorm.DB) (err error) {if !u.IsValid() {return errors.New("rollback invalid user")}return nil
}

更新对象

// 开始事务
BeforeSave
BeforeUpdate
// 关联前的 save
// 更新 db
// 关联后的 save
AfterUpdate
AfterSave
// 提交或回滚事务
func (u *User) BeforeUpdate(tx *gorm.DB) (err error) {if u.readonly() {err = errors.New("read only user")}return
}// 在同一个事务中更新数据
func (u *User) AfterUpdate(tx *gorm.DB) (err error) {if u.Confirmed {tx.Model(&Address{}).Where("user_id = ?", u.ID).Update("verfied", true)}return
}

删除对象

删除时可用的 hook

// 开始事务
BeforeDelete
// 删除 db 中的数据
AfterDelete
// 提交或回滚事务

代码示例:

// 在同一个事务中更新数据
func (u *User) AfterDelete(tx *gorm.DB) (err error) {if u.Confirmed {tx.Model(&Address{}).Where("user_id = ?", u.ID).Update("invalid", false)}return
}

查询对象

查询时可用的 hook

// 从 db 中加载数据
// Preloading (eager loading)
AfterFind

代码示例:

func (u *User) AfterFind(tx *gorm.DB) (err error) {if u.MemberShip == "" {u.MemberShip = "user"}return
}

修改当前操作

func (u *User) BeforeCreate(tx *gorm.DB) error {// 通过 tx.Statement 修改当前操作,例如:tx.Statement.Select("Name", "Age")tx.Statement.AddClause(clause.OnConflict{DoNothing: true})
//向当前的数据库操作添加了一个冲突处理条款,指定如果尝试插入的记录与现有记录发生冲突(例如,违反了唯一性约束),则不执行任何操作
//这个设置通常用于INSERT 操作,以处理可能的重复插入。// tx 是带有 `NewDB` 选项的新会话模式 // 基于 tx 的操作会在同一个事务中,但不会带上任何当前的条件err := tx.First(&role, "name = ?", user.Role).Error// SELECT * FROM roles WHERE name = "admin"// ...return err
}

这段代码的主要作用是在创建 User 记录之前,先查询一个与 User 相关的角色信息,并处理可能的数据库冲突。这个查询操作的结果(是否成功)将决定 BeforeCreate 钩子函数的返回值,从而可能影响 User 记录的创建过程。

相关文章:

gorm框架

连接 需要下载mysql的驱动 go get gorm.io/driver/mysql go get gorm.io/gorm 约定 主键&#xff1a;GORM 使用一个名为ID 的字段作为每个模型的默认主键。表名&#xff1a;默认情况下&#xff0c;GORM 将结构体名称转换为 snake_case 并为表名加上复数形式。 例如&#xf…...

免费送源码:Java+Springboot+MySQL Springboot多租户博客网站的设计 计算机毕业设计原创定制

Springboot多租户博客网站的设计 摘 要 博客网站是当今网络的热点&#xff0c;博客技术的出现使得每个人可以零成本、零维护地创建自己的网络媒体&#xff0c;Blog站点所形成的网状结构促成了不同于以往社区的Blog文化&#xff0c;Blog技术缔造了“博客”文化。本文课题研究的“…...

【ASR技术】WhisperX安装使用

介绍 WhisperX 是一个开源的自动语音识别&#xff08;ASR&#xff09;项目&#xff0c;由 m-bain 开发。该项目基于 OpenAI 的 Whisper 模型&#xff0c;通过引入批量推理、强制音素对齐和语音活动检测等技术。提供快速自动语音识别&#xff08;large-v2 为 70 倍实时&#xf…...

【计算机网络】协议定制

一、结构化数据传输流程 这里涉及协议定制、序列化/反序列化的知识 对于序列化和反序列化&#xff0c;有现成的解决方案&#xff1a;①json ②probuff ③xml 二、理解发送接收函数 我们调用的所有发送/接收函数&#xff0c;根本就不是把数据发送到网络中&#xff01;本质都是…...

【SQL】mysql常用命令

为方便查询&#xff0c;特整理MySQL常用命令。 约定&#xff1a;$后为Shell环境命令&#xff0c;>后为MySQL命令。 1 常用命令 第一步&#xff0c;连接数据库。 $ mysql -u root -p # 进入MySQL bin目录后执行&#xff0c;回车后输入密码连接。# 常用参数&…...

阿里云引领智算集群网络架构的新一轮变革

阿里云引领智算集群网络架构的新一轮变革 云布道师 11 月 8 日~ 10 日在江苏张家港召开的 CCF ChinaNet&#xff08;即中国网络大会&#xff09;上&#xff0c;众多院士、教授和业界技术领袖齐聚一堂&#xff0c;畅谈网络未来的发展方向&#xff0c;聚焦智算集群网络的创新变…...

几何合理的分片段感知的3D分子生成 FragGen - 评测

FragGen 来源于 2024 年 3 月 25 日 预印本的文章&#xff0c;文章题目是 Deep Geometry Handling and Fragment-wise Molecular 3D Graph Generation&#xff0c; 作者是 Odin Zhang&#xff0c;侯廷军&#xff0c;浙江大学药学院。FragGen 是一个基于分子片段的 3D 分子生成模…...

Python爬虫下载新闻,Flask展现新闻(2)

上篇讲了用Python从新闻网站上下载新闻&#xff0c;本篇讲用Flask展现新闻。关于Flask安装网上好多教程&#xff0c;不赘述。下面主要讲 HTML-Flask-数据 的关系。 简洁版 如图&#xff0c;页面简单&#xff0c;主要显示新闻标题。 分页&#xff0c;使用最简单的分页技术&…...

监控易监测对象及指标之:全面监控华为FusionInsight服务

随着大数据技术的广泛应用&#xff0c;华为FusionInsight以其卓越的性能和稳定性&#xff0c;成为了众多企业处理和分析海量数据的首选平台。然而&#xff0c;为了确保FusionInsight服务的持续稳定运行&#xff0c;对其进行全面监控至关重要。本文基于监控易工具&#xff0c;对…...

SQL面试题——蚂蚁SQL面试题 会话分组问题

会话分组问题 这里的分组不是简单的分组,而是会话的分组。 比如说,进入一个网站以后,可以连续的点击很多个页面,后台会记录用户的行为日志; 如果T日上午连续点击几个页面后退出了网站,直到第二天的下午才再次进入网站,单单从时间线上来看,昨天退出的那条日志跟今天进…...

nfs服务器--RHCE

一&#xff0c;简介 NFS&#xff08;Network File System&#xff0c;网络文件系统&#xff09;是FreeBSD支持的文件系统中的一种&#xff0c;它允许网络中的计 算机&#xff08;不同的计算机、不同的操作系统&#xff09;之间通过TCP/IP网络共享资源&#xff0c;主要在unix系…...

React--》如何高效管理前端环境变量:开发与生产环境配置详解

在前端开发中&#xff0c;如何让项目在不同环境下表现得更为灵活与高效&#xff0c;是每个开发者必须面对的挑战&#xff0c;从开发阶段的调试到生产环境的优化&#xff0c;环境变量配置无疑是其中的关键。 env配置文件&#xff1a;通常用于管理项目的环境变量&#xff0c;环境…...

Javascript高级—函数柯西化

函数柯西化&#xff08;经典面试题&#xff09; // 实现一个add方法&#xff0c;使计算结果能够满足如下预期&#xff1a; add(1)(2)(3) 6; add(1, 2, 3)(4) 10; add(1)(2)(3)(4)(5) 15;function add() {// 第一次执行时&#xff0c;定义一个数组专门用来存储所有的参数var…...

Sql进阶:字段中包含CSV,如何通过Sql解析CSV成多行多列?

Sql进阶 一、问题描述二、解决思路<一>、拆成多行<二>、拆成多列 三、代码实现 一、问题描述 Oracle数据库中某个字段value是CLOB类型,存的是csv格式的数据,如下所示 classnovalue1name,age,sex,… ‘李世民’,20,‘M’,…’ ‘李治’,18,‘M’,… ‘武则天’,16…...

linux之调度管理(5)-实时调度器

一、概述 在Linux内核中&#xff0c;实时进程总是比普通进程的优先级要高&#xff0c;实时进程的调度是由Real Time Scheduler(RT调度器)来管理&#xff0c;而普通进程由CFS调度器来管理。 实时进程支持的调度策略为&#xff1a;SCHED_FIFO和SCHED_RR。 SCHED_FIFO&#xff…...

mybatis-plus: mapper-locations: “classpath*:/mapper/**/*.xml“配置!!!解释

和mybatis一样的道理&#xff01;&#xff01;&#xff01;&#xff01;如果不指定这个配置&#xff0c;通常要求 XML 映射文件和 Mapper 接口的包名和结构相同&#xff01;&#xff01;&#xff01;&#xff01; 如果没有配置 mapper-locations&#xff0c;通常文件结构应遵循…...

nacos-operator在k8s集群上部署nacos-server2.4.3版本踩坑实录

文章目录 操作步骤1. 拉取仓库代码2. 安装nacos-operator3. 安装nacos-server 坑点一坑点二nacos-ui页面访问同一集群环境下微服务连接nacos地址配置待办参考文档 操作步骤 1. 拉取仓库代码 &#xff08;这一步主要用到代码中的相关yml文件&#xff0c;稍加修改用于部署容器&…...

面试篇-项目管理

⼀、构建管理 项目为什么选择Maven构建? 选择Maven进行项目构建有以下几个主要原因&#xff1a; 1. 依赖管理&#xff1a;Maven 提供了强大的依赖管理功能&#xff0c;可以自动下载项目所需的第三方库和依赖&#xff0c;并且可以管理这些依赖的版本、范围等信息。这简化了项…...

数仓建设之Oracle常见语法学习

1. 字符串截取 select substr(AAA-BBB, 1, instr(AAA-BBB, -, -1) - 1) 值 from dual; --AAA select substr(AAA-BBB, instr(AAA-BBB, -, -1) 1) 值 from dual; --BBB2. 帆软报表有参数SQL select a.agency_code, a.agency_name, a.agency_typefrom dw.dim_ta_subred_agency…...

物联网智能技术的深入探讨与案例分析

✅作者简介&#xff1a;2022年博客新星 第八。热爱国学的Java后端开发者&#xff0c;修心和技术同步精进。 &#x1f34e;个人主页&#xff1a;Java Fans的博客 &#x1f34a;个人信条&#xff1a;不迁怒&#xff0c;不贰过。小知识&#xff0c;大智慧。 &#x1f49e;当前专栏…...

python语言基础-5 进阶语法-5.2 装饰器-5.2.2 简单装饰器

声明&#xff1a;本内容非盈利性质&#xff0c;也不支持任何组织或个人将其用作盈利用途。本内容来源于参考书或网站&#xff0c;会尽量附上原文链接&#xff0c;并鼓励大家看原文。侵删。 5.2.2 简单装饰器 装饰器的形式就是一个闭包&#xff0c;下面是一个简单的定义并使用…...

TransFormer--解码器:带掩码的多头注意力层

TransFormer--解码器&#xff1a;带掩码的多头注意力层 以英法翻译任务为例&#xff0c;假设训练数据集样本如下表所示。 原句目标翻译I am goodJe vais bienGood morningBonjourThank you very muchMerci beaucoup 上表所示的数据集由两部分组成&#xff1a;原句和目标句。在…...

【ArcGIS微课1000例】0130:图层组详解与使用

文章目录 一、图层组概述二、创建图层组三、在图层组中管理图层四、对话框中图层组的列表一、图层组概述 图层组包含其他图层。图层组有助于对地图中相关类型的图层进行组织,并且可用于定义高级绘制选项。例如,假设在地图上有两个图层分别用于表示铁路和高速公路。您可将这些…...

Linux中配置ntp服务

NTP&#xff1a;是Network Time Protocol的缩写又 称网络时间协议&#xff0c;是用来使计算机时间同步化的一种协议&#xff0c;用来同步网络中各主机的时 间&#xff0c;在linux系统中早期使用ntp来实现&#xff0c;后来使用chrony来实现。Chrony 应用本身已经有 几年了&#…...

微服务day10-Redis面试篇

Redis主从 搭建主从集群 建立集群时主节点会生成同一的replicationID,交给各个从节点。 集群中的缓冲区是一个环型数组&#xff0c;即若从节点宕机时间过长&#xff0c;可能导致命令被覆盖。 主从集群优化 哨兵原理 哨兵是一个集群来确保哨兵不出现问题。 服务状态监控 选举…...

STL序列式容器之list

相较于vector的连续性空间&#xff0c;list相对比较复杂&#xff1b;list内部使用了双向环形链表的方式对数据进行存储&#xff1b;list在增加元素时&#xff0c;采用了精准的方式分配一片空间对数据及附加指针等信息进行存储&#xff1b; list节点定义如下 template<clas…...

docker:基于Dockerfile镜像制作完整案例

目录 摘要目录结构介绍起始目录package目录target目录sh目录init.sh脚本start.sh脚本stop.sh脚本restart.sh脚本 config目录 步骤1、编写dockerfilescript.sh脚本 2、构件镜像查看镜像 3、保存镜像到本地服务器4、复制镜像文件到指定目录&#xff0c;并执行init.sh脚本5、查看挂…...

微信小程序自定义顶部导航栏(适配各种机型)

效果图 1.pages.js&#xff0c;需要自定义导航栏的页面设置"navigationStyle": "custom" 2.App.vue,获取设备高度及胶囊位置 onLaunch: function () {// 系统信息const systemInfo uni.getSystemInfoSync()// 胶囊按钮位置信息const menuButtonInfo uni.…...

sslSocketFactory not supported on JDK 9+

clientBuilder.sslSocketFactory(SSLSocketFactory) not supported on JDK 9 at okhttp3.internal.platform.Jdk9Platform.trustManager(Jdk9Platform.kt:61) at okhttp3.OkHttpClient$Builder.sslSocketFactory(OkHttpClient.kt:751) at 1.升版本4.9.3以上 2、加个函数获取X…...

[Codesys]常用功能块应用分享-BMOV功能块功能介绍及其使用实例说明

官方说明 功能说明 参数 类型 功能 pbyDataSrcPOINTER TO BYTE指向源数组指针uiSizeUINT要移动数据的BYTE数pbyDataDesPOINTER TO BYTE指向目标数组指针 实例应用-ST IF SYSTEM_CLOCK.AlwaysTrue THENCASE iAutoState OF0: //读写完成信号在下次读写信号的上升沿或复位信号…...

温州做网站哪家公司好/seo流量

一、光盘挂载镜像配置yum源1、挂载光盘镜像mount /dev/cdrom /media #将光盘系统文件挂载到 /media文件夹下2、配置光盘yum源 repo配置文件cd /etc/yum.repo.d #切换到yum配置文件目录mkdir repos_bak #创建repos配置文件备份文件夹mv *.repo repos_bak #将…...

中山市建设局网站/如何进行网站性能优化?

我不是Facebook也不是Pinterest 粉丝&#xff0c;所以当朋友Orli发给我 Pinvolve的链接时&#xff0c;我很惊奇&#xff0c;它把 Facebook的动态更新以Pinterest式风格呈现出来&#xff0c;我很喜欢这个。在我眼里它提供了更好地方式来浏览世界上最大的社交网络&#xff0c;即使…...

wordpress调用图片/搜狗官方网站

什么是Service Locator 模式&#xff1f; 服务定位模式&#xff08;Service Locator Pattern&#xff09;是一种软件开发中的设计模式&#xff0c;通过应用强大的抽象层&#xff0c;可对涉及尝试获取一个服务的过程进行封装。该模式使用一个称为"Service Locator"的中…...

建设网站的技术手段/哈尔滨网络推广优化

在子类继承父类中&#xff0c;一般有一行super的语句&#xff0c;需要记住三种使用方法&#xff1a; 1、super.变量/对象名&#xff1b; 使用这种方法可以直接访问父类中的变量或对象&#xff0c;进行修改赋值等操作 2、super.方法名()&#xff1b; 直接访问并调用父类中的…...

厦门专业建站系统制作公司/北京做网站推广

本节书摘来华章计算机《电路分析导论&#xff08;原书第12版&#xff09;》一书中的第2章 &#xff0c;第2.4节&#xff0c;&#xff08;美&#xff09; Robert L.Boylestad 著 陈希有 张新燕 李冠林 等译更多章节内容可以访问云栖社区“华章计算机”公众号查看。 2.4 电流…...

如何设公司产品购物网站/网站建设公司地址在哪

2019独角兽企业重金招聘Python工程师标准>>> 官方地址&#xff1a;http://jquery.malsup.com/block/ 需要使用的js 引入jquery包 引入插件包JQuery BlockUI&#xff08;官方下载相应的js&#xff09; demo 1.直接弹出提示话语 <!DOCTYPE html PUBLIC "-//W…...