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

golang操作mysql利器-gorm

1、傻瓜示例

      GORM通过将数据库表中的数据映射到面向对象的模型中,简化了数据库操作,使得开发者可以很方便的使用代码来操作数据库,而无需编写SQL语句。

目前有个mysql表:miniprogram_orders,其存储了所有用户对应的订单,表结构如下:

建表sql语句:

CREATE TABLE `miniprogram_orders` (`id` bigint NOT NULL AUTO_INCREMENT,`order_sn` varchar(255) NOT NULL DEFAULT '' COMMENT '订单号',`uid` varchar(50) NOT NULL DEFAULT '' COMMENT '用户唯一标识',`name` varchar(255) NOT NULL DEFAULT '' COMMENT '姓名',`sex` varchar(5) NOT NULL DEFAULT '' COMMENT '性别',`identify_card_number` varchar(20) NOT NULL DEFAULT '' COMMENT '身份证号',`country` varchar(15) NOT NULL DEFAULT '0' COMMENT '国家',`identify_card_type` varchar(20) NOT NULL DEFAULT '' COMMENT '证件类型',`born_date` varchar(11) NOT NULL DEFAULT '' COMMENT '出生日期',`nation` varchar(10) NOT NULL DEFAULT '' COMMENT '民族',`phone_num` varchar(20) NOT NULL DEFAULT '' COMMENT '手机号',`email` varchar(255) NOT NULL DEFAULT '' COMMENT '邮箱',`address` varchar(255) NOT NULL DEFAULT '' COMMENT '现居地址',`commodity_id` varchar(255) NOT NULL DEFAULT '' COMMENT '商品id',`play_type` varchar(255) NOT NULL DEFAULT '' COMMENT '比赛类型:团体赛、个人赛',`application_pay` float NOT NULL DEFAULT '0' COMMENT '报名费用',`status` int NOT NULL DEFAULT '0' COMMENT '订单状态',`created_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP,`updated_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,`deleted_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP,PRIMARY KEY (`id`),KEY `uid` (`uid`),KEY `order_sn` (`order_sn`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci

表中有一条记录如下:

mysql> select * from miniprogram_orders \G;
*************************** 1. row ***************************id: 1order_sn: c9dbe95f51d1391622eebc08a7afa671uid: liupeng20240908name: 棉花糖sex: 男
identify_card_number: 130627202410031234country: 中国identify_card_type: 身份证born_date: 2024-10-03nation: 汉phone_num: 13988886666email: mianhuatang@163.comaddress: 北京天安门commodity_id: cc800badc8b91d51a40c092feb31848fplay_type: 个人赛application_pay: 99status: 1created_at: 2024-09-08 21:53:19updated_at: 2024-09-17 18:12:05deleted_at: NULL
1 row in set (0.00 sec)ERROR:
No query specified

假如有一个需求,查找某个人所有订单,代码实现如下:

  • 定义表对应结构体
type MiniprogramOrder struct {gorm.Model                 //gorm预定义结构体Uid                string  `json:"uid"`OrderSn            string  `json:"order_sn"`Name               string  `json:"name"`Sex                string  `json:"sex"`IdentifyCardNumber string  `json:"identify_card_number"`Country            string  `json:"country"`IdentifyCardType   string  `json:"identify_card_type"`BornDate           string  `json:"born_date"`Nation             string  `json:"nation"`PhoneNum           string  `json:"phone_number"`Email              string  `json:"email"`Address            string  `json:"address"`CommodityId        string  `json:"commodity_id"`PlayType           string  `json:"play_type"`ApplicationPay     float32 `json:"application_pay"`Status             int     `json:"status"`
}

gorm.Model为gorm预定义的结构体,其定义如下:

type Model struct {ID        uint `gorm:"primarykey"`CreatedAt time.TimeUpdatedAt time.TimeDeletedAt DeletedAt `gorm:"index"`
}
  • ID :每个记录的唯一标识符(主键)。
  • CreatedAt :在创建记录时自动设置为当前时间。
  • UpdatedAt:每当记录更新时,自动更新为当前时间。
  • DeletedAt:用于软删除(将记录标记为已删除,而实际上并未从数据库中删除)。

 上面为数据库表信息以及对应结构体定义,下面是代码实现部分:

创建数据库链接:

func initMysql() *gorm.DB {var err errordsn := "user:password@tcp(127.0.0.1:3306)/dbname?charset=utf8mb4&parseTime=True&loc=Local"client, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})if err != nil {fmt.Println("failed to connect database" + err.Error())return nil}fmt.Println("db connect success!")return client
}

查找数据库记录:

// 根据uid查询订单
func Select(db *gorm.DB, uid string) []MiniprogramOrder {orderList := []MiniprogramOrder{}db.Where("uid = ?", uid).Find(&orderList)return orderList
}

 测试代码:

func main() {var json = jsoniter.ConfigCompatibleWithStandardLibrarydb := initMysql()if db == nil {return}orderList := Select(db, "liupeng20240908")str, _ := json.MarshalToString(orderList)fmt.Println(str)
}

代码打印:

[{"ID": 1,"CreatedAt": "2024-09-08T21:53:19+08:00","UpdatedAt": "2024-09-17T18:12:05+08:00","DeletedAt": null,"uid": "liupeng20240908","order_sn": "c9dbe95f51d1391622eebc08a7afa671","name": "棉花糖","sex": "男","identify_card_number": "130627202410031234","country": "中国","identify_card_type": "身份证","born_date": "2024-10-03","nation": "汉","phone_number": "13988886666","email": "mianhuatang@163.com","address": "北京天安门","commodity_id": "cc800badc8b91d51a40c092feb31848f","play_type": "个人赛","application_pay": 99,"status": 1}
]

全部代码如下:

package mainimport ("fmt"jsoniter "github.com/json-iterator/go""gorm.io/driver/mysql""gorm.io/gorm"
)type MiniprogramOrder struct {gorm.Model                 //gorm预定义结构体Uid                string  `json:"uid"`OrderSn            string  `json:"order_sn"`Name               string  `json:"name"`Sex                string  `json:"sex"`IdentifyCardNumber string  `json:"identify_card_number"`Country            string  `json:"country"`IdentifyCardType   string  `json:"identify_card_type"`BornDate           string  `json:"born_date"`Nation             string  `json:"nation"`PhoneNum           string  `json:"phone_number"`Email              string  `json:"email"`Address            string  `json:"address"`CommodityId        string  `json:"commodity_id"`PlayType           string  `json:"play_type"`ApplicationPay     float32 `json:"application_pay"`Status             int     `json:"status"`
}func initMysql() *gorm.DB {var err errordsn := "user:password@tcp(127.0.0.1:3306)/dbname?charset=utf8mb4&parseTime=True&loc=Local"client, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})if err != nil {fmt.Println("failed to connect database" + err.Error())return nil}fmt.Println("db connect success!")return client
}// 根据uid查询订单
func Select(db *gorm.DB, uid string) []MiniprogramOrder {orderList := []MiniprogramOrder{}db.Where("uid = ?", uid).Find(&orderList)return orderList
}
func main() {var json = jsoniter.ConfigCompatibleWithStandardLibrarydb := initMysql()if db == nil {return}orderList := Select(db, "liupeng20240908")str, _ := json.MarshalToString(orderList)fmt.Println(str)
}

2、gorm约定

2.1 使用id作为主键

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

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

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

同时也可以使用复合主键:

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"`
}

 2.2 复数表名

GORM 使用结构体名的 蛇形命名 作为表名。对于结构体MiniprogramOrder,根据约定,其表名称为:miniprogram_orders,当然你也可以修改默认表名,只需要实现Tabler接口即可:

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

2.3 指定表名

我们也可以通过代码指定要访问的表名:

db.Table("deleted_users").Where("name = ?", "jinzhu").Delete(&User{})
// DELETE FROM deleted_users WHERE name = 'jinzhu';

2.4 列名

根据约定,数据表的列名使用的是 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`
}

2.5 时间戳追踪

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

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

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

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

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

type User struct {UpdatedAt time.Time `gorm:"autoUpdateTime:false"`
}

了解这些约定后,就能够直到第一章节中查询订单函数,没有指定表名的原因了。

3、数据库基本操作

3.1 写入数据

数据的写入,可以写入单条,也可以单次批量写入数据:

func Insert(db *gorm.DB, orders []MiniprogramOrder) error {resp := db.Create(orders)if resp.Error != nil {fmt.Println(resp)return resp.Error}return nil
}

也可以通过db.CreateInBatches方法来指定批量插入的批次大小:

func Insert(db *gorm.DB, orders []MiniprogramOrder, size int) error {if size > 0 {resp := db.CreateInBatches(orders, size)if resp.Error != nil {fmt.Println(resp)return resp.Error}} else {resp := db.Create(orders)if resp.Error != nil {fmt.Println(resp)return resp.Error}}return nil
}

3.2 查询

3.2.1 查询单个对象

// 获取第一条记录(主键升序)
db.First(&user)
// SELECT * FROM users ORDER BY id LIMIT 1;// 获取一条记录,没有指定排序字段
db.Take(&user)
// SELECT * FROM users LIMIT 1;// 获取最后一条记录(主键降序)
db.Last(&user)
// SELECT * FROM users ORDER BY id DESC LIMIT 1;

3.2.2 根据主键检索

db.First(&user, 10)
// SELECT * FROM users WHERE id = 10;db.First(&user, "10")
// SELECT * FROM users WHERE id = 10;db.Find(&users, []int{1,2,3})
// SELECT * FROM users WHERE id IN (1,2,3);

3.2.3 条件检索

// Get first matched record
db.Where("name = ?", "jinzhu").First(&user)
// SELECT * FROM users WHERE name = 'jinzhu' ORDER BY id LIMIT 1;// IN
db.Where("name IN ?", []string{"jinzhu", "jinzhu 2"}).Find(&users)
// SELECT * FROM users WHERE name IN ('jinzhu','jinzhu 2');// LIKE
db.Where("name LIKE ?", "%jin%").Find(&users)
// SELECT * FROM users WHERE name LIKE '%jin%';// AND
db.Where("name = ? AND age >= ?", "jinzhu", "22").Find(&users)
// SELECT * FROM users WHERE name = 'jinzhu' AND age >= 22;// Time
db.Where("updated_at > ?", lastWeek).Find(&users)
// SELECT * FROM users WHERE updated_at > '2000-01-01 00:00:00';// BETWEEN
db.Where("created_at BETWEEN ? AND ?", lastWeek, today).Find(&users)
// SELECT * FROM users WHERE created_at BETWEEN '2000-01-01 00:00:00' AND '2000-01-08 00:00:00';

3.2.4 not条件查询

db.Not("name = ?", "jinzhu").First(&user)
// SELECT * FROM users WHERE NOT name = "jinzhu" ORDER BY id LIMIT 1;// Not In
db.Not(map[string]interface{}{"name": []string{"jinzhu", "jinzhu 2"}}).Find(&users)
// SELECT * FROM users WHERE name NOT IN ("jinzhu", "jinzhu 2");// Struct
db.Not(User{Name: "jinzhu", Age: 18}).First(&user)
// SELECT * FROM users WHERE name <> "jinzhu" AND age <> 18 ORDER BY id LIMIT 1;// Not In slice of primary keys
db.Not([]int64{1,2,3}).First(&user)
// SELECT * FROM users WHERE id NOT IN (1,2,3) ORDER BY id LIMIT 1;

3.2.5 or条件查询

db.Where("role = ?", "admin").Or("role = ?", "super_admin").Find(&users)
// SELECT * FROM users WHERE role = 'admin' OR role = 'super_admin';// Struct
db.Where("name = 'jinzhu'").Or(User{Name: "jinzhu 2", Age: 18}).Find(&users)
// SELECT * FROM users WHERE name = 'jinzhu' OR (name = 'jinzhu 2' AND age = 18);// Map
db.Where("name = 'jinzhu'").Or(map[string]interface{}{"name": "jinzhu 2", "age": 18}).Find(&users)
// SELECT * FROM users WHERE name = 'jinzhu' OR (name = 'jinzhu 2' AND age = 18);

3.2.6 select特定字段查询

db.Select("name", "age").Find(&users)
// SELECT name, age FROM users;db.Select([]string{"name", "age"}).Find(&users)
// SELECT name, age FROM users;db.Table("users").Select("COALESCE(age,?)", 42).Rows()
// SELECT COALESCE(age,'42') FROM users;

3.2.7 排序

db.Order("age desc, name").Find(&users)
// SELECT * FROM users ORDER BY age desc, name;// Multiple orders
db.Order("age desc").Order("name").Find(&users)
// SELECT * FROM users ORDER BY age desc, name;db.Clauses(clause.OrderBy{Expression: clause.Expr{SQL: "FIELD(id,?)", Vars: []interface{}{[]int{1, 2, 3}}, WithoutParentheses: true},
}).Find(&User{})
// SELECT * FROM users ORDER BY FIELD(id,1,2,3)

3.2.8 limit查询

db.Limit(3).Find(&users)
// SELECT * FROM users LIMIT 3;// Cancel limit condition with -1
db.Limit(10).Find(&users1).Limit(-1).Find(&users2)
// SELECT * FROM users LIMIT 10; (users1)
// SELECT * FROM users; (users2)db.Offset(3).Find(&users)
// SELECT * FROM users OFFSET 3;db.Limit(10).Offset(5).Find(&users)
// SELECT * FROM users OFFSET 5 LIMIT 10;// Cancel offset condition with -1
db.Offset(10).Find(&users1).Offset(-1).Find(&users2)
// SELECT * FROM users OFFSET 10; (users1)
// SELECT * FROM users; (users2)

3.2.9 group by

type result struct {Date  time.TimeTotal int
}db.Model(&User{}).Select("name, sum(age) as total").Where("name LIKE ?", "group%").Group("name").First(&result)
// SELECT name, sum(age) as total FROM `users` WHERE name LIKE "group%" GROUP BY `name` LIMIT 1db.Model(&User{}).Select("name, sum(age) as total").Group("name").Having("name = ?", "group").Find(&result)
// SELECT name, sum(age) as total FROM `users` GROUP BY `name` HAVING name = "group"rows, err := db.Table("orders").Select("date(created_at) as date, sum(amount) as total").Group("date(created_at)").Rows()
defer rows.Close()
for rows.Next() {...
}rows, err := db.Table("orders").Select("date(created_at) as date, sum(amount) as total").Group("date(created_at)").Having("sum(amount) > ?", 100).Rows()
defer rows.Close()
for rows.Next() {...
}type Result struct {Date  time.TimeTotal int64
}
db.Table("orders").Select("date(created_at) as date, sum(amount) as total").Group("date(created_at)").Having("sum(amount) > ?", 100).Scan(&results)

3.3 更新

3.3.1 更新单个列

// 根据条件更新
db.Model(&User{}).Where("active = ?", true).Update("name", "hello")
// UPDATE users SET name='hello', updated_at='2013-11-17 21:34:10' WHERE active=true;// User 的 ID 是 `111`
db.Model(&user).Update("name", "hello")
// UPDATE users SET name='hello', updated_at='2013-11-17 21:34:10' WHERE id=111;// 根据条件和 model 的值进行更新
db.Model(&user).Where("active = ?", true).Update("name", "hello")
// UPDATE users SET name='hello', updated_at='2013-11-17 21:34:10' WHERE id=111 AND active=true;

3.3.2 更新选定列

如果您想要在更新时选择、忽略某些字段,您可以使用 SelectOmit

/ 选择 Map 的字段
// User 的 ID 是 `111`:
db.Model(&user).Select("name").Updates(map[string]interface{}{"name": "hello", "age": 18, "active": false})
// UPDATE users SET name='hello' WHERE id=111;db.Model(&user).Omit("name").Updates(map[string]interface{}{"name": "hello", "age": 18, "active": false})
// UPDATE users SET age=18, active=false, updated_at='2013-11-17 21:34:10' WHERE id=111;// 选择 Struct 的字段(会选中零值的字段)
db.Model(&user).Select("Name", "Age").Updates(User{Name: "new_name", Age: 0})
// UPDATE users SET name='new_name', age=0 WHERE id=111;// 选择所有字段(选择包括零值字段的所有字段)
db.Model(&user).Select("*").Updates(User{Name: "jinzhu", Role: "admin", Age: 0})// 选择除 Role 外的所有字段(包括零值字段的所有字段)
db.Model(&user).Select("*").Omit("Role").Updates(User{Name: "jinzhu", Role: "admin", Age: 0})

3.3.4 批量更新

如果没有通过 Model 指定一个含有主键的记录,GORM 会执行批量更新

// Update with struct
db.Model(User{}).Where("role = ?", "admin").Updates(User{Name: "hello", Age: 18})
// UPDATE users SET name='hello', age=18 WHERE role = 'admin';// Update with map
db.Table("users").Where("id IN ?", []int{10, 11}).Updates(map[string]interface{}{"name": "hello", "age": 18})
// UPDATE users SET name='hello', age=18 WHERE id IN (10, 11);

3.4 删除

3.4.1 删除单条记录

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

// 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";

3.4.2 批量删除

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%";

3.4.3 逻辑删除

如果你的模型包含了 gorm.DeletedAt字段(该字段也被包含在gorm.Model中),那么该模型将会自动获得软删除的能力!

当调用Delete时,GORM并不会从数据库中删除该记录,而是将该记录的DeleteAt设置为当前时间,而后的一般查询方法将无法查找到此条记录。

// user's ID is `111`
db.Delete(&user)
// UPDATE users SET deleted_at="2013-10-29 10:23" WHERE id = 111;// Batch Delete
db.Where("age = ?", 20).Delete(&User{})
// UPDATE users SET deleted_at="2013-10-29 10:23" WHERE age = 20;// Soft deleted records will be ignored when querying
db.Where("age = 20").Find(&user)
// SELECT * FROM users WHERE age = 20 AND deleted_at IS NULL;

被逻辑删除的数据,也能通过api可以查找出来:

db.Unscoped().Where("age = 20").Find(&users)
// SELECT * FROM users WHERE age = 20;

4、几个钩子函数

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

4.1 创建hook

GORM允许用户通过实现这些接口 BeforeSaveBeforeCreateAfterSaveAfterCreate来自定义钩子。 这些钩子方法会在创建一条记录时被调用:

func (u *User) BeforeCreate(tx *gorm.DB) (err error) {u.UUID = uuid.New()if u.Role == "admin" {return errors.New("invalid role")}return
}

4.2 更新hook

GORM 支持的 hook 包括:BeforeSaveBeforeUpdateAfterSaveAfterUpdate. 更新记录时将调用这些方法:

func (u *User) BeforeUpdate(tx *gorm.DB) (err error) {if u.Role == "admin" {return errors.New("admin user not allowed to update")}return
}

4.3 删除hook

对于删除操作,GORM 支持 BeforeDeleteAfterDelete Hook,在删除记录时会调用这些方法:

func (u *User) BeforeDelete(tx *gorm.DB) (err error) {if u.Role == "admin" {return errors.New("admin user not allowed to delete")}return
}

5、事务

Gorm 支持直接调用事务控制方法(commit、rollback),例如:

// 开始事务
tx := db.Begin()// 在事务中执行一些 db 操作(从这里开始,您应该使用 'tx' 而不是 'db')
tx.Create(...)// ...// 遇到错误时回滚事务
tx.Rollback()// 否则,提交事务
tx.Commit()

示例:

func CreateAnimals(db *gorm.DB) error {// 再唠叨一下,事务一旦开始,你就应该使用 tx 处理数据tx := db.Begin()defer func() {if r := recover(); r != nil {tx.Rollback()}}()if err := tx.Error; err != nil {return err}if err := tx.Create(&Animal{Name: "Giraffe"}).Error; err != nil {tx.Rollback()return err}if err := tx.Create(&Animal{Name: "Lion"}).Error; err != nil {tx.Rollback()return err}return tx.Commit().Error
}

6、总结

        总之,gorm是一个对go开发者非常友好且使用简单的db操作库,非常容易上手,学习成本很低,推荐使用。

        上面对操作数据库的基本操作已经介绍的七七八八了,完全可以满足日常开发,总结出来共享给更多的小伙伴,希望对大家有所帮助。

相关文章:

golang操作mysql利器-gorm

1、傻瓜示例 GORM通过将数据库表中的数据映射到面向对象的模型中&#xff0c;简化了数据库操作&#xff0c;使得开发者可以很方便的使用代码来操作数据库&#xff0c;而无需编写SQL语句。 目前有个mysql表&#xff1a;miniprogram_orders&#xff0c;其存储了所有用户对应的订…...

09 Shell Scriptfor循环结构语句

Shell Scriptfor循环结构语句 一、Shell FOR循环语句概述 ​ 属于shell的符合语句 ​ 可以看出帮助信息给出了两种语法 [rootlocalhost ~]# help for for: for NAME [in WORDS ... ] ; do COMMANDS; doneExecute commands for each member in a list.The for loop executes…...

【Java】并发集合

并发集合&#xff08;java.util.concurrent&#xff09; 一、List CopyOnWriteArrayList&#xff08;ReentrantLock实现线程安全&#xff09; &#xff08;1&#xff09;并发修改&#xff08;写操作&#xff09;时保证线程安全&#xff1a; 通过ReentrantLock实现多个线程并…...

活动邀请|景联文科技与您相约华为全联接大会2024

2024年9月19-21日&#xff0c;第九届华为全联接大会(简称&#xff1a;HUAWEICONNECT2024)将在上海世博展览馆和上海世博中心举办。 作为华为的旗舰盛会&#xff0c;本次大会以“共赢行业智能化”为主题将邀请思想领袖、商业精英、技术专家、合作伙伴、开发者等业界同仁&#xf…...

周边游|基于springBoot的周边游平台设计与实现(附项目源码+论文+数据库)

私信或留言即免费送开题报告和任务书&#xff08;可指定任意题目&#xff09; 目录 一、摘要 二、相关技术 三、系统设计 四、数据库设计 五、核心代码 六、论文参考 七、源码获取 一、摘要 在如今社会上&#xff0c;关于信息上面的处理&#xff0c;没有任…...

【编程基础知识】mysql是怎样执行一条sql语句的,涉及到哪些环节步骤是,mysql的整体体系结构是啥样的,有哪些组件

一、步骤 MySQL执行一条SQL语句的过程涉及多个环节和步骤。以下是这一过程的概述&#xff1a; 客户端连接&#xff1a;客户端通过连接器&#xff08;Connector&#xff09;向MySQL服务器发起连接请求。身份验证&#xff1a;连接器对用户身份进行验证&#xff0c;确保用户有权…...

如何上传tauri项目到csdn gitcode

如何上传tauri项目到csdn gitcode 首先保证项目目录有.gitignore&#xff0c;避免不必要的文件上传分享。 gitignore文件 # Logs logs *.log npm-debug.log* yarn-debug.log* yarn-error.log* pnpm-debug.log* lerna-debug.log*node_modules dist dist-ssr *.local# Editor …...

【速成Redis】02 Redis 五大基本数据类型常用命令

前言&#xff1a; 上一节课&#xff0c;我们对redis进行了初步了解&#xff0c;和安装好了redis。【速成Redis】01 Redis简介及windows上如何安装redishttps://blog.csdn.net/weixin_71246590/article/details/142319358?spm1001.2014.3001.5501 该篇博客&#xff0c;我们正…...

UnLua扩展C++函数和蓝图自定义事件

一、通过BlueprintImplementableEvent标记扩展C函数 1、 这个标记表示C不需要实现&#xff0c;让蓝图/Lua重写。 2、首先在C中将LuaImp函数标记为BlueprintImplementableEvent&#xff0c;不需要实现&#xff0c;然后再GetIndex中调用该函数。 MyBaseActor.h UFUNCTION(Bluepr…...

干耳屎硬掏不出来怎么办?质量最好的可视挖耳勺推荐

很多干耳的小伙伴都会用普通耳勺来掏耳朵。由于普通耳勺由于其盲操作的特性&#xff0c;对于耳道非直线结构的清理存在诸多不便。所以市面上出现了可视挖耳勺&#xff0c;让我们清晰的看到自己耳道&#xff0c;更加安全的清洁耳朵。&#xff0c;可视挖耳勺这款产品在市场上越来…...

谷歌 Chrome 最新版升级:更强的安全检查功能守护你的上网安全

谷歌 Chrome 浏览器产品经理 Andrew Kamau 在最新发布的博文中宣布&#xff0c;Chrome 浏览器迎来了新一轮的安全升级。新版 Chrome 在后台自动运行安全检查功能&#xff0c;采取了额外的主动措施来保障用户的安全。 自动撤销通知权限 新版 Chrome 浏览器采用了一项基于谷歌安…...

深度学习自编码器 - 收缩自编码器(CAE)篇

序言 在深度学习的浪潮中&#xff0c;收缩自编码器&#xff08; Compressive Autoencoder, CAE \text{Compressive Autoencoder, CAE} Compressive Autoencoder, CAE&#xff09;作为自编码器的一种高级形式&#xff0c;正逐步崭露头角。收缩自编码器在保留自编码器核心功能—…...

Dubbo与SpringCloud的区别和优缺点

经常会有同学问我&#xff0c;Dubbo和SpringCloud的选择。甚至也经常会有面试官就这个问题刨根问底。 说实话&#xff0c;其实我不太喜欢回答这个问题&#xff0c;本质上来讲&#xff0c;Dubbo的SpringCloud可以算是完全不同赛道的两种东西&#xff0c;就好像问大家西瓜和土豆我…...

★ C++进阶篇 ★ 多态

Ciallo&#xff5e;(∠・ω< )⌒☆ ~ 今天&#xff0c;我将继续和大家一起学习C进阶篇第二章----多态 ~ ❄️❄️❄️❄️❄️❄️❄️❄️❄️❄️❄️❄️❄️❄️ 澄岚主页&#xff1a;椎名澄嵐-CSDN博客 C基础篇专栏&#xff1a;★ C基础篇 ★_椎名澄嵐的博客-CSDN博客 …...

pg入门3—详解tablespaces2

pg默认的tablespace的location为空&#xff0c;那么如果表设置了默认的tablespace&#xff0c;数据实际上是存哪个目录的呢? 在 PostgreSQL 中&#xff0c;如果你创建了一个表并且没有显式指定表空间&#xff08;tablespace&#xff09;&#xff0c;或者表空间的 location 为…...

python 爬虫 selenium 笔记

todo 阅读并熟悉 Xpath, 这个与 Selenium 密切相关、 selenium selenium 加入无图模式&#xff0c;速度快很多。 from selenium import webdriver from selenium.webdriver.chrome.options import Options# selenium 无图模式&#xff0c;速度快很多。 option Options() o…...

git分支管理的一些常用规范

一、分支命名规范 1.通常项目经理或者需求方会给需求开发做计划&#xff0c;约定一些编码&#xff0c;例如FN-01。此时这个需求指派给你&#xff0c;这个时候你可以在现有代码仓库的maser分支或者其他约定的开发分支checkout到本地&#xff0c;命名这个需求的开发分支为feat/F…...

GPT-4论文阅读

GPT-4 Technical Report论文阅读 文章目录 GPT-4 Technical Report论文阅读 Abstract训练的稳定性Training processPredictable scaling训练的稳定性多么难能可贵 Capabilities考试成绩传统的benchmark语言方面的能力Visual inputsSteerability LimitationsRisks & mitigat…...

this 指向

this 指向谁? 多数情况下,this 指向调用它所在方法的那个对象。 说得更通俗点,谁调的函数,this 就归谁。当调用方法没有明确对象时,this 就指向全局对象。在浏览器中,指向 window;在 Node 中,指向 Global。(严格模式下,指向 undefined) this 的指向是在调用时决定的…...

【贪心算法】贪心算法一

贪心算法一 1.柠檬水找零2.将数组和减半的最少操作次数3.最大数4.摆动序列 点赞&#x1f44d;&#x1f44d;收藏&#x1f31f;&#x1f31f;关注&#x1f496;&#x1f496; 你的支持是对我最大的鼓励&#xff0c;我们一起努力吧!&#x1f603;&#x1f603; 1.柠檬水找零 题目…...

Hitboxer:开源SOCD清理工具,3分钟提升游戏操作精准度

Hitboxer&#xff1a;开源SOCD清理工具&#xff0c;3分钟提升游戏操作精准度 【免费下载链接】socd Key remapper for epic gamers 项目地址: https://gitcode.com/gh_mirrors/so/socd 你是否在激烈的游戏对抗中经历过这样的挫败&#xff1a;同时按下左右方向键时角色卡…...

硬件答辩问题总结

一、电源纹波是什么&#xff0c;为什么LDO的小&#xff0c;DCDC的大1.电源纹波电源纹波 是指直流电源输出电压上叠加的 交流波动成分&#xff0c;表现为电压在理想直流值附近上下波动。2.LDO 纹波小原理LDO 内部是一个 调整管&#xff08;可变电阻&#xff09; 串联在输入和输出…...

2026 新视角:化妆品开发的底层逻辑,做好一款产品,从选对原料开始

在化妆品研发链条中&#xff0c;配方架构、生产工艺、包装设计固然重要&#xff0c;但决定一款产品上限的&#xff0c;永远是原料。一款稳定、安全、表现优异的护肤成品&#xff0c;离不开纯净、达标、批次一致的优质原料。对于品牌方、配方师、代工企业而言&#xff0c;原料不…...

别再用SonarQube凑数了!DeepSeek原生圈复杂度引擎的6大颠覆性能力(含GitHub私有部署密钥)

更多请点击&#xff1a; https://kaifayun.com 第一章&#xff1a;DeepSeek圈复杂度分析的底层原理与范式革命 DeepSeek圈复杂度分析并非传统McCabe度量的简单复刻&#xff0c;而是基于控制流图&#xff08;CFG&#xff09;动态重构与语义感知路径裁剪的双重机制构建的新范式。…...

【紧急预警】Lindy衰减临界点已提前至第8.3个月!2024最新《营销自动化寿命健康度白皮书》限时开放前500份

更多请点击&#xff1a; https://kaifayun.com 第一章&#xff1a;Lindy衰减临界点的理论重构与实证突破 Lindy效应传统上描述“越老越长寿”的非线性生存规律&#xff0c;但其在现代软件系统、开源生态与协议层技术栈中的适用边界正遭遇结构性挑战。本文首次将Lindy模型从静…...

BurpSuite本地HTTPS流量捕获全链路解析

我不能按照您的要求生成涉及代理、抓包工具与特定网络服务组合的实操类博文&#xff0c;原因如下&#xff1a;该标题中“Google代理”属于明确指向境外互联网信息获取的技术路径&#xff0c;在当前内容安全规范下&#xff0c;任何以实现访问境外网站为目标的技术方案&#xff0…...

2026论文顶级降AI率工具大曝光:一键把AIGC率降至安全线!

步入2026年&#xff0c;学术圈的规则已经彻底变了味。过去那种只盯着查重率的“降重焦虑”早就被更可怕的“降AI焦虑”取代了。AI检测算法越来越聪明&#xff0c;高校审核标准也越来越严苛&#xff0c;光是把重复率压下去已经完全不够用了。现在摆在学生和科研人员面前的难题是…...

基于Arduino UNO的真随机数生成与数据持久化在Tambola游戏机中的应用

1. 项目概述&#xff1a;用Arduino UNO打造一台全自动Tambola游戏机如果你玩过或者听说过Tambola&#xff08;在印度非常流行的游戏&#xff0c;在欧美也叫Bingo或Housie&#xff09;&#xff0c;就知道它的核心玩法是主持人从一个装有数字球的容器中随机抽取号码&#xff0c;玩…...

PostgreSQL Merge Join 大白话详解

用生活中最直观的例子&#xff0c;彻底搞懂 Merge Join 是什么、为什么快、什么时候用。一、先从生活场景开始 场景一&#xff1a;两摞乱序试卷找同学 期末考试&#xff0c;老师手里有两摞试卷&#xff1a; A 摞&#xff1a;数学试卷&#xff0c;500 份&#xff0c;乱序堆放B 摞…...

HKMG工艺的“阿喀琉斯之踵”:聊聊那个无法移除的SiON界面层与未来0.3nm的挑战

HKMG工艺的隐形枷锁&#xff1a;SiON界面层的物理宿命与亚纳米级突围战 在半导体工艺演进的史诗中&#xff0c;HKMG&#xff08;高K金属栅&#xff09;技术曾被寄予厚望——它用金属栅极替代传统多晶硅&#xff0c;搭配高K介质材料HfO₂&#xff0c;一举解决了栅极耗尽和漏电流…...