Go语言数据库框架——xorm
文章目录
- XORM
- 1 概念
- 1.1 ORM
- 1.2 Mysql
- 1.3 Mysql命令大全
- 2 XORM 的基本使用
- 2.1 下载xorm
- 2.2 安装驱动
- 2.3 xorm引擎
- 2.3.1 创建引擎
- 2.3.2 打印日志
- 2.3.3 连接池
- 2.3.4 名称映射规则
- 2.3.5 数据类型对应规则
- 2.3.6 xorm对数据类型的定义
- 2.4 创建引擎组
- 2.5 基本操作
- 3 XORM数据库操作
- 3.1 表操作
- 3.2 增
- 3.3 删除
- 3.4 查改
XORM
1 概念
1.1 ORM
ORM 是 Object Relational Mapping 的缩写,译为“对象关系映射”框架。
ORM 框架是一种数据持久化技术,是一种为了解决面向对象与关系型数据库中数据类型不匹配的技术,它通过描述对象与数据库表之间的映射关系,自动将应用程序中的对象持久化到关系型数据库的表中。
Gorm和Xorm都是Go语言的ORM库,其他相关的数据库框架库参考:https://my.oschina.net/u/168737/blog/1531834
执行一下两条命令 安装mysql引擎 以及 安装xorm库
go get -u github.com/go-sql-driver/mysql
go get github.com/go-xorm/xorm
1.2 Mysql
下载安装:https://cloud.tencent.com/developer/article/1636375
启动/停止服务:net start/stop mysql
登录:mysql -u root -p密码
列出数据库:show databases,退出数据库:quit
1.3 Mysql命令大全
Mysql常用命令大全:https://www.cnblogs.com/bluecobra/archive/2012/01/11/2318922.html
CREATE DATABASE IF NOT EXISTS golang;
USE golang;
DROP TABLE IF EXISTS user;CREATE TABLE user (id INT NOT NULL AUTO_INCREMENT,name VARCHAR(30) NOT NULL,PRIMARY KEY (id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;INSERT INTO classes(id, name) VALUES (1, 'sommer');
INSERT INTO classes(id, name) VALUES (2, 'Jack');
INSERT INTO classes(id, name) VALUES (3, 'hapu');
INSERT INTO classes(id, name) VALUES (4, 'Dim');select * from user;
2 XORM 的基本使用
参考资源:
xorm操作
使用go xorm来操作mysql的方法实例
xorm使用
xorm官方文档
Go语言的ORM库xorm实战篇
xorm基础
2.1 下载xorm
go get github.com/go-xorm/xorm
go get github.com/go-xorm/cmd
2.2 安装驱动
go get github.com/go-sql-driver/mysql //Mysql
go get github.com/ziutek/mymysql/godrv //MyMysql
go get github.com/lib/pq //Postgres
go get github.com/mattn/go-sqlite3 //SQLite
go get github.com/denisenkom/go-mssqldb //MSSQL
2.3 xorm引擎
Engine 引擎用于对单个数据库进行操作
Engine Group 引擎用于对读写分离的数据库或者负载均衡的数据库进行操作
2.3.1 创建引擎
import (_ "github.com/go-sql-driver/mysql""xorm.io/xorm"
)var engine *xorm.Enginefunc main() {var err error/**配置连接数据库信息格式:用户名:密码@(数据库服务器地址:端口)/数据库名称?charset=字符集*/engine, err = xorm.NewEngine("mysql", "root:root@(127.0.0.1)/golang?charset=utf8")engine.Ping() //连接测试defer engine.Close() //延迟关闭数据库
}
2.3.2 打印日志
engine.ShowSQL(true)//在控制台打印出生成的SQL语句;
engine.Logger().SetLevel(core.LOG_DEBUG)//在控制台打印调试及以上的信息;
--------------------------------------------------------------------
// 将日志保存为文件
f, err := os.Create("sql.log")
if err != nil {println(err.Error())return
}
engine.SetLogger(xorm.NewSimpleLogger(f))
2.3.3 连接池
如果需要设置连接池的空闲数大小,使用 engine.SetMaxIdleConns() 来实现。
如果需要设置最大打开连接数,则使用 engine.SetMaxOpenConns() 来实现。
如果需要设置连接的最大生存时间,则使用 engine.SetConnMaxLifetime() 来实现。
2.3.4 名称映射规则
xorm 内置了三种 Mapper 实现:names.SnakeMapper
, names.SameMapper
和names.GonicMapper
。
SnakeMapper 支持struct为驼峰式命名,表结构为下划线命名之间的转换,这个是默认的Maper; // user_table——UserTable,user_id——UserId
SameMapper 支持结构体名称和对应的表名称以及结构体field名称与对应的表字段名称相同的命名;
GonicMapper 和SnakeMapper很类似,但是对于特定词支持更好,比如ID会翻译成id而不是i_d。
engine.SetMapper(names.GonicMapper{})
// 给表加前缀
tbMapper := names.NewPrefixMapper(names.SnakeMapper{}, "prefix_")
engine.SetTableMapper(tbMapper)
// 加后缀
names.NewSuffixMapper(names.SnakeMapper{}, "suffix")
表名的优先级顺序如下:
engine.Table() 指定的临时表名优先级最高
TableName() string 其次
Mapper 自动映射的表名优先级最后
字段名的优先级顺序如下:
结构体tag指定的字段名优先级较高 xorm:"'column_name'"
Mapper 自动映射的表名优先级较低
type User struct {Id int //`xorm:"INT 'id'"`Name string //`xorm:"VARCHAR(30) 'name'"`
}
2.3.5 数据类型对应规则
Go中的Type类型 | XORM映射的Type类型 |
---|---|
implemented Conversion | Text |
int, int8, int16, int32, uint, uint8, uint16, uint32 | Int |
int64, uint64 | BigInt |
float32 | Float |
float64 | Double |
complex64, complex128 | Varchar(64) |
[]uint8 | Blob |
array, slice, map except []uint8 | Text |
bool | Bool |
string | Varchar(255) |
time.Time | DateTime |
cascade struct | BigInt |
struct | Text |
Others | Text |
2.3.6 xorm对数据类型的定义
name | 当前field对应的字段的名称,可选,如不写,则自动根据field名字和转换规则命名 |
---|---|
pk | 是否是Primary Key |
autoincr | 是否是自增 |
[not ]null 或 notnull | 是否可以为空 |
unique | 是否是唯一 |
index | 是否是索引 |
extends | 应用于一个匿名成员结构体或者非匿名成员结构体之上 |
- | Field将不进行字段映射 |
-> | Field将只写入到数据库而不从数据库读取 |
<- | Field将只从数据库读取,而不写入到数据库 |
created | Field将在Insert时自动赋值为当前时间 |
updated | Field将在Insert或Update时自动赋值为当前时间 |
deleted | Field将在Delete时设置为当前时间,并且当前记录不删除 |
version | Field将会在insert时默认为1,每次更新自动加1 |
default 0或default(0) | 设置默认值,紧跟的内容如果是Varchar等需要加上单引号 |
json | 表示内容将先转成Json格式,然后存储到数据库中,数据库中的字段类型可以为Text或者二进制 |
comment | 设置字段的注释(当前仅支持mysql) |
//用户表
type UserTable struct {UserId int64 `xorm:"pk autoincr"` //用户id 主键UserName string `xorm:"varchar(32)"` //用户名称UserAge int64 `xorm:"default 1"` //用户年龄UserSex int64 `xorm:"default 0"` //用户性别
}
//学生表
type StudentTable struct {Id int64 `xorm:"pk autoincr"` //主键 自增StudentName string `xorm:"varchar(24)"` //StudentAge int `xorm:"int default 0"`StudentSex int `xorm:"index"` //sex为索引
}//人类表
type PersonTable struct {Id int64 `xorm:"pk autoincr"` //主键自增PersonName string `xorm:"varchar(24)"` //可变字符PersonAge int `xorm:"int default 0"` //默认值PersonSex int `xorm:"notnull"` //不能为空City CityTable `xorm:"-"` //不映射该字段 那就不会在数据库里面创建该字段
}
2.4 创建引擎组
在xorm中,通过创建引擎组EngineGroup来实现对从数据库(Master/Slave)读写分离的支持。在创建引擎章节中,我们已经介绍过了,在xorm里面,可以同时存在多个Orm引擎,一个Orm引擎称为Engine,一个Engine一般只对应一个数据库,而EngineGroup一般则对应一组数据库。EngineGroup通过调用xorm.NewEngineGroup生成,如:
import (_ "github.com/lib/pq""github.com/xormplus/xorm"
)var eg *xorm.EngineGroupfunc main() {conns := []string{"postgres://postgres:root@localhost:5432/test?sslmode=disable;","postgres://postgres:root@localhost:5432/test1?sslmode=disable;","postgres://postgres:root@localhost:5432/test2?sslmode=disable",}var err erroreg, err = xorm.NewEngineGroup("postgres", conns)
}
or
import (_ "github.com/lib/pq""github.com/xormplus/xorm"
)var eg *xorm.EngineGroupfunc main() {var err errormaster, err := xorm.NewEngine("postgres", "postgres://postgres:root@localhost:5432/test?sslmode=disable")if err != nil {return}slave1, err := xorm.NewEngine("postgres", "postgres://postgres:root@localhost:5432/test1?sslmode=disable")if err != nil {return}slave2, err := xorm.NewEngine("postgres", "postgres://postgres:root@localhost:5432/test2?sslmode=disable")if err != nil {return}slaves := []*xorm.Engine{slave1, slave2}eg, err = xorm.NewEngineGroup(master, slaves)
}
创建完成EngineGroup之后,并没有立即连接数据库,此时可以通过eg.Ping()来进行数据库的连接测试是否可以连接到数据库,该方法会依次调用引擎组中每个Engine的Ping方法。另外对于某些数据库有连接超时设置的,可以通过起一个定期Ping的Go程来保持连接鲜活。EngineGroup可以通过eg.Close()来手动关闭,但是一般情况下可以不用关闭,在程序退出时会自动关闭。
- NewEngineGroup方法
func NewEngineGroup(args1 interface{}, args2 interface{}, policies ...GroupPolicy) (*EngineGroup, error)
前两个参数的使用示例如上,有两种模式。
模式一:通过给定DriverName,DataSourceName来创建引擎组,每个引擎使用相同的Driver。每个引擎的DataSourceNames是[]string类型,第一个元素是Master的DataSourceName,之后的元素是Slave的DataSourceName。
模式一:通过给定*xorm.Engine
,[]*xorm.Engine
来创建引擎组,每个引擎可以使用不同的Driver。第一个参数为Master的*xorm.Engine
,第二个参数为Slave的[]*xorm.Engine
。
NewEngineGroup方法,第三个参数为
policies
,为Slave给定负载策略,该参数将在负载策略章节详细介绍,如示例中未指定,则默认为轮询负载策略。
- Master方法
func (eg *EngineGroup) Master() *Engine
返回Master数据库引擎 - Slave方法
func (eg *EngineGroup) Slave() *Engine
依据给定的负载策略返回一个Slave数据库引擎 - Slaves方法
func (eg *EngineGroup) Slaves() []*Engine
返回所以Slave数据库引擎 - GetSlave方法
func (eg *EngineGroup) GetSlave(i int) *Engine
依据一组Slave数据库引擎[]*xorm.Engine
下标返回指定Slave数据库引擎。通过给定DriverName,DataSourceName来创建引擎组,则DataSourceName的第二个元素的数据库为下标0的Slave数据库引擎。 - SetPolicy方法
func (eg *EngineGroup) SetPolicy(policy GroupPolicy) *EngineGroup
设置引擎组负载策略
2.5 基本操作
package mainimport ("fmt"_ "github.com/go-sql-driver/mysql" //千万不要忘记导入"github.com/go-xorm/xorm""xorm.io/core"
)var engine *xorm.Engine
func main() {//1.创建数据库引擎对象var err error engine, err = xorm.NewEngine("mysql", "root:root@(127.0.0.1:3306)/golang?charset=utf8mb4")engine.Ping() //连接测试,连接正常输出 PING DATABASE mysqlif err != nil {panic(err.Error())}// 2.延迟关闭数据库引擎defer engine.Close()// 3.数据库引擎设置engine.ShowSQL(true) //将sql语句显示在控制台中engine.Logger().SetLevel(core.LOG_DEBUG) // 设置日志级别,在控制台打印调试及以上的信息// 查询表中所有的数据session := engine.Table("user")count, err := session.Count()if err != nil {panic(err.Error())}fmt.Println(count)// 使用原生sql语句进行查询result, err := engine.Query("select * from user")if err != nil {panic(err.Error())}for key, value := range result {fmt.Println(key, value)}
}
测试
package main
import ("fmt""github.com/go-xorm/xorm""github.com/go-xorm/core"_ "github.com/go-sql-driver/mysql"
)
// 对应数据库的tablename必须为student
// 执行mysql时,对应的字段为xxx,yyy,zzz; 也可以省掉,默认的mysql字段为id,username,address
type Student struct {Id int `xorm:"INT(11) 'xxx'"`Username string `xorm:"VARCHAR(64) 'yyy'"`Address string `xorm:"VARCHAR(256) 'zzz'"`
}
func main() {engine, err := xorm.NewEngine("mysql", "root@/taoge?charset=utf8") // dbname是taogeif err != nil{fmt.Println(err)return}// 如下Ping可以不要// if err := engine.Ping(); err != nil{// fmt.Println(err)// return// }//engine.ShowSQL(true) // 显示SQL的执行, 便于调试分析engine.SetTableMapper(core.SnakeMapper{})st1 := new(Student)st1.Username = "taoge"st1.Address = "China"affected, err := engine.Insert(st1)fmt.Println(affected)st2 := new(Student)result,err := engine.Where("xxx=?", 1).Get(st2)fmt.Println(result)fmt.Println(st2.Username)fmt.Println(st2.Address)
}
创建数据库:
CREATE TABLE `student` (`xxx` int(11) NOT NULL AUTO_INCREMENT,`yyy` varchar(64) NOT NULL,`zzz` varchar(256) NOT NULL ,PRIMARY KEY (`xxx`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
3 XORM数据库操作
3.1 表操作
engine.DBMetas() // 获取数据库中所有的表,字段,索引的信息。
engine.CreateTables() //创建表,参数为一个或多个空的对应Struct的指针。
engine.IsTableEmpty() //判断表是否为空,参数和 CreateTables 相同
engine.IsTableExist() //判断表是否存在
engine.DropTables() //删除表 参数为一个或多个空的对应Struct的指针或者表的名字。如果为string传入,则只删除对应的表,如果传入的为Struct,则删除表的同时还会删除对应的索引。
engine.CreateIndexes //根据struct中的tag来创建索引
engine.CreateUniques //根据struct中的tag来创建唯一索引err := engine.Sync(new(User), new(Group)) //同步数据库结构
err := engine.Sync2(new(User), new(Group))// 导出数据库的结构和数据
engine.DumpAll(w io.Writer)
engine.DumpAllToFile(fpath string)
// 执行SQL脚本
engine.Import(r io.Reader)
engine.ImportFile(fpath string)
//判断一个表当中内容是否为空
personEmpty, err := engine.IsTableEmpty(new(PersonTable))
if err != nil {panic(err.Error())
}
if personEmpty {fmt.Println("人员表是空的!")
}else{fmt.Println("人员表不为空!")
}//判断表结构是否存在
studentExist, err := engine.IsTableExist(new(StudentTable))
if err != nil {panic(err.Error())
}
if studentExist {fmt.Println("学生表存在!")
}else{fmt.Println("学生表不存在!")
}
3.2 增
// 插入单条记录
user1 := new(User)
user1.Id = 6
user1.Name = "Dim"
affected, err := engine.Insert(user1)
fmt.Println("插入单条数据:", affected, err)// 插入多条数据
users := make([]*User, 3)
users[0] = new(User)
users[0].Id = 11
users[0].Name = "name11"
users[1] = new(User)
users[1].Id = 12
users[1].Name = "name12"
users[2] = new(User)
users[2].Id = 13
users[2].Name = "name13"
affects, errs := engine.Insert(&users)
fmt.Println("插入多条数据:", affects, errs)
3.3 删除
删除数据Delete
方法,参数为struct的指针并且成为查询条件。
软删除Deleted,不真正的删除数据,而是标记一个删除时间。
// 删除
affdel, errdel := engine.Delete(user)
fmt.Println(affdel, errdel)
3.4 查改
func main(){engine, err := xorm.NewEngine("mysql", "root:root@/elmcms?charset=utf8")if err != nil {panic(err.Error())}//条件查询//1.ID查询//首先你得要有一个结构体来存放查询出来的数据var person PersonTable//select * from person_table where id = 1 并且get只获取到一条记录哈!engine.Id(1).Get(&person)fmt.Println(person)fmt.Println("----------------------------")//2.where多条件查询//首先你得要有一个结构体来存放查询出来的数据var person1 PersonTable//select * from person_table where person_age = 26 and person_sex = 2engine.Where(" person_age = ? and person_sex = ?", 30, 1).Get(&person1)fmt.Println(person1)fmt.Println("----------------------------")//3.and条件查询//首先你得要有一个结构体来存放查询出来的数据var persons []PersonTable//select * from person_table where person_age = 26 and person_sex = 2 find 会返回一条或者多条记录err = engine.Where(" person_age = ?", 30).And("person_sex = ?", 1).Find(&persons)if err != nil {panic(err.Error())}fmt.Println(persons)fmt.Println("----------------------------")//4.or条件查询var personArr []PersonTable//select * from person_table where person_age = 26 or person_sex = 1err = engine.Where(" person_age = ?", 26).Or("person_sex = ?", 1).Find(&personArr)if err != nil {panic(err.Error())}fmt.Println(personArr)fmt.Println("----------------------------")//5.原生sql语句查询 支持likevar personNative []PersonTable//执行原生的sql语句err = engine.SQL(" select * from person_table where person_name like '%i%' ").Find(&personNative)if err != nil {panic(err.Error())}fmt.Println(personNative)fmt.Println("----------------------------")//6.排序条件查询var personOrderBy []PersonTable//select * from person_table orderby person_age 升序排列//engine.OrderBy(" person_age ").Find(&personsOrderBy) 不写desc默认就是asc升序排序err = engine.OrderBy(" person_age desc ").Find(&personOrderBy)if err != nil {panic(err.Error())}fmt.Println(personOrderBy)fmt.Println("----------------------------111")//7.查询特定字段var personCols []PersonTableengine.Cols("person_name", "person_age").Find(&personCols)for _,col := range personCols {fmt.Println(col)}//fmt.Println(personCols)fmt.Println("----------------------------")//增加记录//插入你得先有数据 弄到结构体里面去personInsert := PersonTable{PersonName: "wahaha",PersonAge: 40,PersonSex: 10,}rowNum, err := engine.Insert(&personInsert)fmt.Println(rowNum) //rowNum表示受影响的行数fmt.Println("----------------------------")//删除操作personDelete := PersonTable{}//根据id删除rowNum1, err := engine.Id(4).Delete(&personDelete)fmt.Println(rowNum1) //rowNum1也是表示受影响的行数fmt.Println("----------------------------")//更新操作personUpdate := PersonTable{PersonName: "胡绍良",PersonAge: 30,PersonSex: 1,}rowNum2, err := engine.Id(1).Update(&personUpdate)fmt.Println(rowNum2) // rowNum2也是表示受影响的行数fmt.Println("----------------------------")//统计功能countcount, err := engine.Count(new(PersonTable))fmt.Println("persontable表总记录数:",count)//事务操作personsArray := []PersonTable{PersonTable{PersonName: "Jack",PersonAge: 28,PersonSex: 1,},PersonTable{PersonName: "Mali",PersonAge: 28,PersonSex: 1,},PersonTable{PersonName: "Ruby",PersonAge: 28,PersonSex: 1,},}session := engine.NewSession()session.Begin()for i:=0;i<len(personsArray);i++{_, err = session.Insert(personsArray[i])if err != nil {session.Rollback()session.Close()}}err = session.Commit()session.Close()if err != nil {panic(err.Error())}}//人员结构表
type PersonTable struct {Id int64 `xorm:"pk autoincr"`PersonName string `xorm:"varchar(24)"`PersonAge int `xorm:"int default 0"`PersonSex int `xorm:"notnull"`City CityTable `xorm:"-"`
}type CityTable struct {CityName stringCityLongitude float32CityLatitude float32}
Go语言数据库框架——xorm相关推荐
- Gorm—Go语言数据库框架
文章目录 一.GORM简介 1.什么是Gorm? 2.为什么选择GORM? 3.如何使用GORM? 4.约定大于配置大于编码 GORM 默认使用ID作为表的主键 GORM 默认使用结构体名的 snak ...
- 在线车辆推荐网 Python语言+Django框架+Mysql数据库 基于用户、物品的协同过滤推荐算法 开发在线汽车推荐系统 二手车网站推荐系统 分布式大数据、机器学习、人工智能开发
在线车辆推荐网 Python语言+Django框架+Mysql数据库 基于用户.物品的协同过滤推荐算法 开发在线汽车推荐系统 二手车网站推荐系统 分布式大数据.机器学习.人工智能开发 CarRecom ...
- Java-ORM数据库框架CDM介绍
cdm-core Cdm Framework 一个使用简单,零配置,容错率高,效率的Java™ ORM 数据库框架 ✨ 特性 使用简单 没有依赖,一行代码即可初始化连接,调用接口像使用脚本语言一样畅爽 ...
- Go实战--也许最快的Go语言Web框架kataras/iris初识三(Redis、leveldb、BoltDB)
生命不止,继续 go go go !!! 之前介绍了iris框架,介绍了如何使用basic认证.Markdown.YAML.Json等: Go实战–也许最快的Go语言Web框架kataras/iri ...
- 干货分享:六个知名的Go语言web框架
框架一直是敏捷开发中的利器,能让开发者很快的上手并做出应用,甚至有的时候,脱离了框架,一些开发者都不会写程序了.成长总不会一蹴而就,从写出程序获取成就感,再到精通框架,快速构造应用,当这些方面都得心应 ...
- 安卓进阶系列-06数据库框架(LitePal)的使用
LitePal的使用 背景 安卓内置了一个轻量数据库SQLite,然而很多时候使用SQLite是不方便的,更多开发者习惯服务器部署MySQL之类的数据库,而且复杂的SQL语言对于很多没有系统学习过数据 ...
- Go 语言 Gin 框架实战项目笔记
Go 语言 Gin 框架实战 后端 Goland 操作 创建项目 运行项目 数据库操作 jwt.Response 配置管理 获取请求参数 数据验证 使用 UUID 前端 环境搭建 创建项目 ESLin ...
- go web框架_干货分享:六个知名的Go语言web框架
框架一直是敏捷开发中的利器,能让开发者很快的上手并做出应用,甚至有的时候,脱离了框架,一些开发者都不会写程序了.成长总不会一蹴而就,从写出程序获取成就感,再到精通框架,快速构造应用,当这些方面都得心应 ...
- 微信 WCDB 正式开源——高效易用的移动数据库框架
前沿介绍 腾讯开源微信数据库框架WCDB,他是一个高效.完整.易用的移动数据库框架,基于SQLCipher,支持iOS, macOS和Android. 便捷地定义表.索引.约束,并进行增删改查操作 项 ...
最新文章
- 精通python-精通Python设计模式
- Linux 使用ntpdate自动对时
- 【深度学习】Panoptic FCN:真正End-to-End的全景分割
- cygwin This indicates that the /etc/passwd (and possibly /etc/group) files should be rebuilt 问题解决办法
- axure html显示效果,Axure RP基础篇: 实现循环显示效果的两种方法
- redis中zset底层实现原理
- markdown备忘
- 1.7 什么时候该改变开发_测试集和指标
- 智能玩具 数据采集 首页展示 注册 登录 自动登录 二维码图片
- 罗永浩回应做主播赚钱还债;360 否认裁员;Kubernetes 1.18 版本发布| 极客头条
- python微博爬虫实战_Python爬虫实战演练:爬取微博大V的评论数据
- 关于Linux下使用Windows应用程序的尝试总结
- C# 程序中使用 SQLite 数据库
- 国赛助力:第三类边界条件热传导方程及基于三对角矩阵的数值计算MATLAB实现(2020A)
- Apple苹果EDI案例
- 原生js或uni-app生成二维码(可修改二维码样式,带logo)
- DMIS 5.3 编程基本要义
- Mac 更新系统后无法正常启动
- 我跑了香港六家银行,把境外开户的事整明白了
- Python笔记 | 数据筛选
热门文章
- java 集成grizzly_使用Grizzly的嵌入式Java服务器:如何启用http2
- 黑客如何赚钱?黑客是怎么赚钱的
- 3度带6度带换算以及带号计算
- centos7下安装Acunetix wvs 12.x详细过程
- 期刊论文格式要求笔记
- 教育已成中国人不折不扣的国耻
- 2022年在uniapp中引入vant Weapp
- springboot+maven/gradle整合swag及生成静态文档
- mysql checksum_mysql8 参考手册--CHECKSUM TABLE语句
- 大学计算机作业实验六PPT,实验六MSI计数器应用.ppt