文档

https://learnku.com/docs/gorm/v2/v2_release_note/9756
https://gorm.cn/zh_CN/docs/

下载安装

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

简单示例

package main

import (
"fmt"
"time"
"gorm.io/driver/mysql"
"gorm.io/gorm"
"gorm.io/gorm/logger"
) // 模型定义
type Product struct {
ID uint
Code string
Price uint
CreateAt time.Time
UpdateAt time.Time
} func main(){
// gorm数据库提前创建好
dsn := "root:123456@tcp(127.0.0.1:3306)/gorm?charset=utf8mb4&parseTime=True&loc=Local"
// 创建连接
db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{
Logger: logger.Default.LogMode(logger.Silent),
})
if err != nil{
fmt.Printf("conncetion failed, err:%v", err)
}
// 迁移创建表,默认创建到数据库的表名为结构体名+s
db.AutoMigrate(&Product{}) // 创建一条数据
product := Product{
ID: 1,
Code: "10086",
Price: 120,
CreateAt: time.Now(),
UpdateAt: time.Now(),
}
db.Create(&product) // 读
var product Product
db.First(&product, 1) // 根据整形主键查找
db.First(&product, "code = ?", "D42") // 查找code字段值为D42 // 更新单条
db.Model(&product).Update("Price", 200) //将表products的price字段的值更新为200
// 更新多个字段
db.Model(&product).Updates(Product{Price:200, Code:"F42"})// 仅更新非零值字段
// 使用map类型更新
db.Model(&product).Updates(map[string]interfaces{}{
"Price": 200,
"Code": "F42"
}) // 删除
db.Delete(&product, 1) // 根据主键删除 }

声明模型

// 模型定义
type User struct{
ID uint
Name string
Email *string
Age uint8
Birthday *time.Time
MemberNumber sql.NullString
ActivedAt sql.NullTime
CreateAt time.Time
UpdateAt time.Time
} // gorm内部自己的结构体gorm.Model,可以直接嵌套到自己的结构体中
type Model struct{
ID uint `gorm:"primaryKey"`
CreateAt time.Time
UpdateAt time.Time
DeleteAt gorm.DeleteAt `gorm:"index"`
} // 创建/更新时间
type User struct {
CreatedAt time.Time // 在创建时,如果该字段值为零值,则使用当前时间填充
UpdatedAt int // 在创建时该字段值为零值或者在更新时,使用当前时间戳秒数填充
} // 正常结构体字段通过标签嵌入
type Author struct{
Name string
Email string
}
type Blog struct{
ID int
Author Author `gorm:"embedded"
Upvotes int32`
} // 通过标签来为db中的字段名添加前缀
type Blog struct{
ID int
Author Author `gorm:"embedded;embeddedPrefix:author_"`
Upvotes int32
}
// 等效于
type Blog struct {
ID int
Author Author `gorm:"embedded;embeddedPrefix:author_"`
Upvotes int32
}
// 等效于
type Blog struct {
ID int64
AuthorName string
AuthorEmail string
Upvotes int32
}

修改表名

package main

import (
"gorm.io/driver/mysql"
"gorm.io/gorm"
) type Student struct{ // 对应到 students这个表名
Id int // id
Name String // name
// Score float32 // score
// tag方式
Rank float32 `gorm:"column:score"` //score
// UpdateAt time.Time // update_at
} // 修改表名 默认表名是结构体名小写+s
func (Student) TableName() string{
return "student"
}

字段标签

标签名 说明
column 指定 db 列名
type 列数据类型,推荐使用兼容性好的通用类型,例如:所有数据库都支持 bool、int、uint、float、string、time、bytes 并且可以和其他标签一起使用,例如:not nullsize, autoIncrement… 像 varbinary(8) 这样指定数据库数据类型也是支持的。在使用指定数据库数据类型时,它需要是完整的数据库数据类型,如:MEDIUMINT UNSINED not NULL AUTO_INSTREMENT
size 指定列大小,例如:size:256
primaryKey 指定列为主键
unique 指定列为唯一
default 指定列的默认值
precision 指定列的精度
scale 指定列大小
not null 指定列为 NOT NULL
autoIncrement 指定列为自动增长
embedded 嵌套字段
embeddedPrefix 嵌入字段的列名前缀
autoCreateTime 创建时追踪当前时间,对于 int 字段,它会追踪时间戳秒数,您可以使用 nano/milli 来追踪纳秒、毫秒时间戳,例如:autoCreateTime:nano
autoUpdateTime 创建/更新时追踪当前时间,对于 int 字段,它会追踪时间戳秒数,您可以使用 nano/milli 来追踪纳秒、毫秒时间戳,例如:autoUpdateTime:milli
index 根据参数创建索引,多个字段使用相同的名称则创建复合索引,查看 索引 获取详情
uniqueIndex index 相同,但创建的是唯一索引
check 创建检查约束,例如 check:age > 13,查看 约束 获取详情
<- 设置字段写入的权限, <-:create 只创建、<-:update 只更新、<-:false 无写入权限、<- 创建和更新权限
-> 设置字段读的权限,->:false 无读权限
- 忽略该字段,- 无读写权限

mysql驱动程序的一些高级配置

db, err := gorm.Open(mysql.New(mysql.Config{
DSN: "gorm:gorm@tcp(127.0.0.1:3306)/gorm?charset=utf8&parseTime=True&loc=Local", // DSN data source name
DefaultStringSize: 256, // string 类型字段的默认长度
DisableDatetimePrecision: true, // 禁用 datetime 精度,MySQL 5.6 之前的数据库不支持
DontSupportRenameIndex: true, // 重命名索引时采用删除并新建的方式,MySQL 5.7 之前的数据库和 MariaDB 不支持重命名索引
DontSupportRenameColumn: true, // 用 `change` 重命名列,MySQL 8 之前的数据库和 MariaDB 不支持重命名列
SkipInitializeWithVersion: false, // 根据当前 MySQL 版本自动配置
}), &grom.Config{})

gorm 增删改查

gorm 增

// 结构体定义
type User struct{
ID uint
Name string
Email *string
Age uint8
Birthday *time.Time
MemberNumber sql.NullString
ActivedAt sql.NullTime
CreateAt time.Time
UpdateAt time.Time
} // helper function
func timePtr(t time.Time) *time.Time{
return &t
} // 创建一条数据
// Birthday为指针类型,需要创建一个helper函数来返回time.Time的地址,不能直接使用&来直接取地址
user := User{Name: "jinzhu", Age: 18, Birthday: timePtr(time.Now())}
result := db.Create(&user)
fmt.Println(user.ID) // 返回数据的主键
fmt.Println(result.RowsAffected) // 插入记录的条数 // 选定字段创建
user := User{Name: "liuwei", Age: 28, Birthday: timePtr(time.Now()), CreateAt: time.Now()}
db.Select("Name", "Age", "CreateAt").Create(&user) // Omit排除选定字段
user := User{Name: "jack", Age: 28, Birthday: timePtr(time.Now()), CreateAt: time.Now()}
db.Omit("Age", "CreateAt").Create(&user) // 钩子,创建记录时会自动调用这些方法
// BeforeSave/BeforeCreate, AfterSave/AfterCreate
func (u *User) BeforeCreate(tx *gorm.DB)(err error){
fmt.Println("创建之前调用...")
return nil
}
user := User{Name: "JOJO", Age: 24, Birthday: timePtr(time.Now()), CreatedAt: time.Now()}
db.Create(&user) // 批量插入
var users = []User{{Name: "qiqi1"}, {Name: "qiqi2"}, {Name: "qiqi3"}}
db.Create(&users)
for _, user := range users {
fmt.Println(user.ID)
} // 使用map创建
db.Model(&User{}).Create(map[string]interface{}{
"Name":"wanglei",
"Age": 25,
})
// 批量map插入
db.Model(&User{}).Create([]map[string]interface{}{
{"Name":"xiao1", "Age": 22},
{"Name":"xiao2", "Age": 23},
{"Name":"xiao3", "Age": 24},
}) // 关联创建(一对一),外键会自动关联
db.Create(&User{
Name: "liuwei",
CreditCard: CreditCard{Number: "12345678"}
}) // 跳过关联创建数据
user := User{Name:"wanglei", CreditCard: CreditCard{Number: "11111111"}}
db.Omit("CreditCard").Create(&user)
// 跳过所有关联clause.Associations
db.Omit(clause.Associations).Create(&user) // uuid
go get -u github.com/satori/go.uuid
// 简单使用
u, _ := uuid.NewV4() //uuid.UUID类型,NewV4()每次返回不同uuid // 默认值使用标签default
func (u *User) BeforeCreate(tx *gorm.DB) (err error) {
u.UUID = uuid.NewV4().String()
return nil
} type User struct {
ID int64
Name string `gorm:"default: galeone"`
Age int64 `gorm:"default:18"`
UUID string
}
func main(){
// 默认会自动创建uuid
db.Create(&User{Name: "liuwei1", Age: 28})
db.Create(&User{Name: "liuwei2", Age: 29})
} // 默认值零值问题
// 当Age传入0时,存入到数据时会被识别为default,即使用default的值18
db.Create(&User{Name: "liuwei3", Age: 0}) // 零值问题解决
// 将Age的类型int64改为指针类型*int64
type User struct {
ID int64
Name string `gorm:"default: galeone"`
Age *int64 `gorm:"default:18"`
UUID string
}

gorm 查

var user User

//获取第一条记录(默认按主键升序)
db.First(&user)
fmt.Println(user.ID)
fmt.Println(user.Name) // 获取第一条记录,没有指定排序字段
db.Take(&user)
fmt.Println(user.ID)
fmt.Println(user.Name) // 获取最后一条记录
db.Last(&user) //如果struct没有显示的定义主键,则按第一个字段排序
type Language struct {
Code string
Name string
}
db.First(&Language{}) // 主键检索
// 只支持整形,字符串会导致sql注入问题
// 查询id=10的数据
db.First(&user, 10)
// 查询id在1,2,3中的
db.Find(&user, []int{1,2,3}) // 检索对象
// 获取全部数据,传入对象
db.Find(&user) //获取第一条匹配的记录
db.Where("name = ?", "jinzhu").First(&user) // 获取全部匹配记录
db.Where("name <> ?", "jinzhu").Find(&user) // IN
db.Where("name IN ?", []string{"jinzhu", "jinzhu 2"}).Find(&user) // LIKE
db.Where("name LIKE ?", "%jin%").Find(&user) //AND
db.Where("name = ? AND age >= ?", "jinzhu", "22").Find(&user) // Time
db.Where("updated_at > ?", lastWeek).Find(&user) // BETWEEN
db.Where("created_at BETWEEN ? AND ?", lastWeek, today).Find(&user) // struct类型查询
// 当使用结构作为条件查询时,GORM 只会查询非零值字段
db.Where(&User{Name: "jinzhu", Age: 20}).First(&user)
// Age不会作为查询条件
db.Where(&User{Name: "jinzhu", Age: 0}).First(&user) // Map类型查询,可以使用零值作为查询条件
db.Where(map[string]interface{}{"name": "jinzhu", "age": 20}).Find(&user) // 主键切片
db.Where([]int64{20,21,22}).Find(&user) // 内联条件,用法与where相同
db.Find(&user, "name = ?", "jinzhu") // Not条件
db.Not("name = ?", "jinzhu").First(&user) // Or条件
db.Where("role = ?", "admin").Or("role = ?", "super_admin").Find(&user) // 查询指定字段
db.Select("name", "age").Find(&user) // COALESCE()函数返回传入的参数中第一个非null的值
db.Table("users").Select("COALESCE(age,?)", 42).Rows()
// SELECT COALESCE(age,'42') FROM users; // Order排序
db.Order("age desc, name").Find(&user)
// 指定多个字段排序
db.Order("id desc").Order("age asc").Find(&users) //Limit限制返回的数量
db.Limit(3).Find(&user) // Offset跳过指定的数量返回
db.Offset(3).Find(&user) // Group分组 Having分组后过滤
type result struct{
Date time.Time
Total 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` db.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()
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()
for rows.Next() {
...
} type Result struct {
Date time.Time
Total int64
}
db.Table("orders").Select("date(created_at) as date, sum(amount) as total").Group("date(created_at)").Having("sum(amount) > ?", 100).Scan(&results) // Distinct 去重
db.Distinct("name", "age").Order("name, age desc").Find(&result) // Joins,左查询,右查询,内联查询
type result struct{
Name string
Email string
}
db.Model(&User{}).Select("users.name, emails.email").Joins("left join emails on emails.user_id = users.id").Scan(&result{}) rows, err := db.Table("users").Select("users.name, emails.email").Joins("left join emails on emails.user_id = users.id").Rows()
for rows.Next() {
...
} db.Table("users").Select("users.name, emails.email").Joins("left join emails on emails.user_id = users.id").Scan(&results) // 带参数的多表连接
db.Joins("JOIN emails ON emails.user_id = users.id AND emails.email = ?", "jinzhu@example.org").Joins("JOIN credit_cards ON credit_cards.user_id = users.id").Where("credit_cards.number = ?", "411111111111").Find(&user) // Joins预加载,查询本表的同时将相关的外键表也同时查询出来
db.Joins("Company").Find(&users) // Scan结果至struct,用法于Find类似
type Result struct{
Name string
Age int
}
var result Result
db.Table("users").Select("name", "age").Where("name = ?", "auto").Scan(&result) // 原生sql Raw
db.Raw("SELECT name, age FROM users WHERE name = ?", "Antonio").Scan(&result)

gorm 更新

// Save保存
type User struct{
ID int64
Name string
Age int64
Birthday time.Time
UpdateAt time.Time
}
var user User
db.First(&user)
user.Name = "jinzhu666"
user.Age = 100
db.Save(&user) // 更新单个列,必须指定条件,且该对象主键有值
// 当active=true时,更新name的值为hello
db.Model(&User{}).Where("active = ?", true).Update("name", "hello") // 更新多列
// 根据struct更新,只会更新非零值的字段
db.Model(&user).Updates(User{Name: "hello", Age: 13, Active: false}) // 根据map更新属性
db.Model(&user).Updates(map[string]interfaces{}{
"name": "hello",
"age": 18,
"actived": false
}) // 更新钩子
// 更新记录时会被自动调用
func (u *User) BeforeUpdate(tx *gorm.DB)(err error){
if u.Role == "admin"{
return errors.New("admin user not allowed to update")
}
return
} // 批量更新Updates
db.Model(User{}).Where("role = ?", "admin").Updates(User{Name: "hello", Age: 18}) // 使用sql表达式更新
// product 的 ID 是 `3`
DB.Model(&product).Update("price", gorm.Expr("price * ? + ?", 2, 100))
// UPDATE "products" SET "price" = price * 2 + 100, "updated_at" = '2013-11-17 21:34:10' WHERE "id" = 3; // 在更新时修改值
若要在 Before 钩子中改变要更新的值,如果它是一个完整的更新,可以使用 Save;否则,应该使用 scope.SetColumn ,例如:
func (user *User) BeforeSave(scope *gorm.Scope) (err error) {
if pw, err := bcrypt.GenerateFromPassword(user.Password, 0); err == nil {
scope.SetColumn("EncryptedPassword", pw)
}
} db.Model(&user).Update("Name", "jinzhu")

gorm 删除

// 删除一条记录,删除对象需要指定主键,否则会触发批量删除
var email Email
email.Id = 10
db.Delete(&email) // 带条件删除
db.Where("name = ?", "jinzhu").Delete(&email) // 根据主键删除
db.Delete(&User{}, 10)
var user User
db.Delete(&user, []int{1,2,3}) // 删除钩子
func (u *User) BeforeDelete(tx *gorm.DB) (err error) {
if u.Role == "admin" {
return errors.New("admin user not allowed to delete")
}
return
} // 批量删除,必须加条件
db.Where("email LIKE ?", "%jinzhu%").Delete(Email{})
db.Delete(Email{}, "email LIKE ?", "%jinzhu%")

创建表,一对一/一对多/多对多关联表

// 一对一
type CreditCard struct {
gorm.Model
Number string
UserID uint
} type User struct {
gorm.Model
Name string
CreditCard CreditCard
} func main() {
dsn := "root:123456@tcp(localhost:3306)/test?charset=utf8mb4&parseTime=True&loc=Local"
db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})
if err != nil {
fmt.Printf("connection failed, err:%v", err)
}
// 注意一下结构体的顺序
db.AutoMigrate(&User{}, &CreditCard{})
} // 一对多 User 有多张 CreditCard,UserID 是外键
type User struct {
gorm.Model
CreditCards []CreditCard // 切片
} type CreditCard struct {
gorm.Model
Number string
UserID uint
} // 对多对
// 会在两个 model 中添加一张连接表,使用AutoMigrate创建表时,会自动创建第三表
// User 拥有并属于多种 language,`user_languages` 是连接表
type User struct {
gorm.Model
Languages []Language `gorm:"many2many:user_languages;"`
} type Language struct {
gorm.Model
Name string
} // 多对多,自定义第三张连接表
type Person struct {
ID int
Name string
Addresses []Address `gorm:"many2many:person_addresses;"`
} type Address struct {
ID uint
Name string
} type PersonAddress struct {
PersonID int
AddressID int
CreatedAt time.Time
DeletedAt gorm.DeletedAt
} func (PersonAddress) BeforeCreate(db *gorm.DB) error {
// ...
} // 修改 Person 的 Addresses 字段的连接表为 PersonAddress
// PersonAddress 必须定义好所需的外键,否则会报错
err := db.SetupJoinTable(&Person{}, "Addresses", &PersonAddress{})

重写外键名

//默认的外键使用拥有者的类型名加上主字段名
//如下:其外键一般是 CompanyID
type User struct {
gorm.Model
Name string
CompanyRefer int
Company Company `gorm:"foreignKey:CompanyRefer"`
// 使用 CompanyRefer 作为外键
} type Company struct {
ID int
Name string
}

更改外键

// 默认外键都是使用主键id作为外键
type User struct {
gorm.Model
Name string
CompanyID string
Company Company `gorm:"references:Code"` // 使用 Code 作为外键
} type Company struct {
ID int
Code string
Name string
}

外键约束

// 你可以通过为标签 constraint 配置 OnUpdate、OnDelete 实现外键约束,在使用 GORM 进行迁移时它会被创建
type User struct {
gorm.Model
Name string
CompanyID int
Company Company `gorm:"constraint:OnUpdate:CASCADE,OnDelete:SET NULL;"`
} type Company struct {
ID int
Name string
}

反向引用(多对多)

// User 拥有并属于多种 language,`user_languages` 是连接表
type User struct {
gorm.Model
Languages []*Language `gorm:"many2many:user_languages;"`
} type Language struct {
gorm.Model
Name string
Users []*User `gorm:"many2many:user_languages;"`
}

关联标签

标签 描述
foreignKey 指定外键
references 指定引用
polymorphic 指定多态类型
polymorphicValue 指定多态值、默认表名
many2many 指定连接表表名
joinForeignKey 指定连接表的外键
joinReferences 指定连接表的引用外键
constraint 关系约束,例如:OnUpdateOnDelete

预加载

// 查找一张表的时候,将另外一张表的数据也同时查询出来,用于优化查询
type User struct {
gorm.Model
Username string
Orders []Order
} type Order struct {
gorm.Model
UserID uint
Price float64
} // 查找 user 时预加载相关 Order
db.Preload("Orders").Find(&users) db.Preload("Orders").Preload("Profile").Preload("Role").Find(&users) // Joins预加载,多用于一对一关系, inner join加载
db.Joins("Company").Joins("Manager").Joins("Account").First(&user, 1) // 预加载全部关联clause.Associations
type User struct {
gorm.Model
Name string
CompanyID uint
Company Company
Role Role
}
db.Preload(clause.Associations).Find(&users)

gorm入门学习的更多相关文章

  1. vue入门学习(基础篇)

    vue入门学习总结: vue的一个组件包括三部分:template.style.script. vue的数据在data中定义使用. 数据渲染指令:v-text.v-html.{{}}. 隐藏未编译的标 ...

  2. Hadoop入门学习笔记---part4

    紧接着<Hadoop入门学习笔记---part3>中的继续了解如何用java在程序中操作HDFS. 众所周知,对文件的操作无非是创建,查看,下载,删除.下面我们就开始应用java程序进行操 ...

  3. Hadoop入门学习笔记---part3

    2015年元旦,好好学习,天天向上.良好的开端是成功的一半,任何学习都不能中断,只有坚持才会出结果.继续学习Hadoop.冰冻三尺,非一日之寒! 经过Hadoop的伪分布集群环境的搭建,基本对Hado ...

  4. PyQt4入门学习笔记(三)

    # PyQt4入门学习笔记(三) PyQt4内的布局 布局方式是我们控制我们的GUI页面内各个控件的排放位置的.我们可以通过两种基本方式来控制: 1.绝对位置 2.layout类 绝对位置 这种方式要 ...

  5. PyQt4入门学习笔记(一)

    PyQt4入门学习笔记(一) 一直没有找到什么好的pyqt4的教程,偶然在google上搜到一篇不错的入门文档,翻译过来,留以后再复习. 原始链接如下: http://zetcode.com/gui/ ...

  6. Hadoop入门学习笔记---part2

    在<Hadoop入门学习笔记---part1>中感觉自己虽然总结的比较详细,但是始终感觉有点凌乱.不够系统化,不够简洁.经过自己的推敲和总结,现在在此处概括性的总结一下,认为在准备搭建ha ...

  7. Retrofit 入门学习

    Retrofit 入门学习官方RetrofitAPI 官方的一个例子 public interface GitHubService { @GET("users/{user}/repos&qu ...

  8. MyBatis入门学习教程-使用MyBatis对表执行CRUD操作

    上一篇MyBatis学习总结(一)--MyBatis快速入门中我们讲了如何使用Mybatis查询users表中的数据,算是对MyBatis有一个初步的入门了,今天讲解一下如何使用MyBatis对use ...

  9. opengl入门学习

    OpenGL入门学习 说起编程作图,大概还有很多人想起TC的#include <graphics.h>吧? 但是各位是否想过,那些画面绚丽的PC游戏是如何编写出来的?就靠TC那可怜的640 ...

  10. Swift入门学习之一常量,变量和声明

    版权声明:本文为博主原创文章,未经博主允许不得转载. 转载请表明出处:http://www.cnblogs.com/cavalier-/p/6059421.html Swift入门学习之一常量,变量和 ...

随机推荐

  1. [转帖]Linux中./configure、make、make install命令详解

    简单来说,make 是编译,make install 是安装.   总结:linux编译安装中configure.make和make install各自的作用  • ./configure是用来检测你 ...

  2. [转帖]013 Linux 搞懂「文件所属者更改及权限的赋予」从未如此简单 (chmod、chgrp、chown)

    https://my.oschina.net/u/3113381/blog/5435014   01 一图详解「ls -l」 02 两种符号区分表示文件和目录 -(横线) # 表示非目录文件 d # ...

  3. openEuler technical-certification

    https://gitee.com/meitingli/technical-certification/ 介绍 存放openEuler技术测评相关的文档,包括技术测评标准.流程.指导性文档等 技术测评 ...

  4. 银河麒麟(Ubuntu)无法上网问题的解决方法

    最近部门借了几台银河麒麟的服务器. 因为有特殊用途, 不允许连接互联网,所以没办法只能搭建一个小的局域网进行处理. 但是发现在搭建过程中遇到了一些坑, 之前协助同事解决odoo问题时也遇到过, 当时本 ...

  5. 文心一言 VS 讯飞星火 VS chatgpt (187)-- 算法导论14.1 4题

    四.用go语言,写出一个递归过程 OS-KEY-RANK(T,k),以一棵顺序统计树T和一个关键字k作为输入,要求返回 k 在由 T 表示的动态集合中的秩.假设 T 的所有关键字都不相同. 文心一言, ...

  6. Vue基础系列文章11---router基本使用

    1.系统中引入路由js文件,加两个连接,分别到用户管理和用户注册页面 <router-link to="/user">用户列表</router-link> ...

  7. 单片机 IAP 功能基础开发篇之APP升级(二)

    1.前言 上一篇单片机 IAP 功能基础开发篇之APP升级(一)讲到了单片机 IAP 功能给 APP 程序升级的设计思路,这篇介绍的是具体实现方式. 下一篇单片机 IAP 功能基础开发篇之APP升级( ...

  8. Windows平台安装Oracle11.2.0.4客户端报错INS-30131

    之前为解决EXP-00003错误给出了安装Oracle11.2.0.4的解决方案,自己测试是没问题的,客户自己安装反馈遇到报错INS-30131,MOS有一篇文章: E1: DB: Error INS ...

  9. 6.用户输入和 while 循环--《Python编程:从入门到实践》

    6.1 input 函数 函数input()接受一个参数:即要向用户显示的提示或说明.input 将用户输入解释为字符串. name = input("Please enter your n ...

  10. Excel-批量填充数字

    1.一般情况下,都是使用鼠标左右键拖动来实现数据的填充的 2.但是填充1200列,下拉拖动就非常麻烦,可以首先定位到A200. 在屏幕左侧中央处找到剪切板下方的"A1"字样,鼠标单 ...