sql转struct
6338 | |
sql转struct
功能介绍
1.支持多种数据库的建表 sql转struct, 其中包含(pg、oracle、mysql)等数据库; 建表语句, 建表语句, 建表语句(重要的说3遍)
2.在转换 sql 的时候, 需要确认下是否需要切换处理类型, 暂时支持3种处理方式(normal, postgresql, oracle), 默认: normal.
说明: 不能在 sql 中包含注释内容(即: -- xxx
或 # xxx
); 由于此工具是通过 ; 来分割语句处理. 所有 normal 状态下可以同时处理多个建表语句; postgresql 和 oracle 由于需要解析注释, 只支持单个建表语句.
3.支持自定义过滤不需要的字段, 多个字段通过 , 隔开.
4.默认注入 json tag, 需要多个的时候通过 , 隔开
示例
mysql 建表语句
CREATE TABLE if not exists user (
id int NOT NULL AUTO_INCREMENT,
name varchar(10) NOT NULL COMMENT '姓名',
gender tinyint NOT NULL DEFAULT 0 COMMENT '性别 0-未知 1-男 2-女',
age int NOT NULL COMMENT '年龄',
created_date datetime DEFAULT CURRENT_TIMESTAMP,
updated_date datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (id)
);
处理后
type UserInfo struct {
Id int32 `json:"id,omitempty"`
Name string `json:"name,omitempty"` // 姓名
Gender int8 `json:"gender,omitempty"` // 性别 0-未知 1-男 2-女
Age int32 `json:"age,omitempty"` // 年龄
CreatedDate string `json:"created_date,omitempty"`
UpdatedDate string `json:"updated_date,omitempty"`
}
pgsql 建表语句
CREATE TABLE if not exists user (
id character varying(32) NOT NULL DEFAULT sys_guid(),
name character varying(10) NOT NULL,
gender tinyint NOT NULL,
age tinyint NOT NULL,
created_date timestamp without time zone DEFAULT now(),
updated_date timestamp without time zone DEFAULT now(),
CONSTRAINT user_pkey PRIMARY KEY (id)
);
COMMENT ON TABLE user IS '用户表';
COMMENT ON COLUMN user.id IS '主键';
COMMENT ON COLUMN user.name IS '姓名';
COMMENT ON COLUMN user.gender IS '性别 0-未知 1-男 2-女';
COMMENT ON COLUMN user.age IS '年龄';
COMMENT ON COLUMN user.created_date IS '创建时间';
COMMENT ON COLUMN user.updated_date IS '更新时间';
处理后
type UserInfo struct {
Id string `json:"id,omitempty"` // 主键
Name string `json:"name,omitempty"` // 姓名
Gender int8 `json:"gender,omitempty"` // 性别 0-未知 1-男 2-女
Age int8 `json:"age,omitempty"` // 年龄
CreatedDate string `json:"created_date,omitempty"` // 创建时间
UpdatedDate string `json:"updated_date,omitempty"` // 更新时间
}
oracle 建表语句
CREATE TABLE if not exists user (
id character varying(32) NOT NULL DEFAULT sys_guid(),
name character varying(10) NOT NULL,
gender tinyint NOT NULL,
age tinyint NOT NULL,
created_date date default sysdate,,
updated_date date default sysdate,,
CONSTRAINT user_pkey PRIMARY KEY (id)
);
COMMENT ON TABLE user IS '用户表';
COMMENT ON COLUMN user.id IS '主键';
COMMENT ON COLUMN user.name IS '姓名';
COMMENT ON COLUMN user.gender IS '性别 0-未知 1-男 2-女';
COMMENT ON COLUMN user.age IS '年龄';
COMMENT ON COLUMN user.created_date IS '创建时间';
COMMENT ON COLUMN user.updated_date IS '更新时间';
处理后
type UserInfo struct {
Id string `json:"id,omitempty"` // 主键
Name string `json:"name,omitempty"` // 姓名
Gender int8 `json:"gender,omitempty"` // 性别 0-未知 1-男 2-女
Age int8 `json:"age,omitempty"` // 年龄
CreatedDate string `json:"created_date,omitempty"` // 创建时间
UpdatedDate string `json:"updated_date,omitempty"` // 更新时间
}
自荐 轻量级spellsql-orm
项目背景
1.spellsql 最初是为了能够高效的拼接 sql 和自动打印最终 sql, 最后为了解决繁琐的查询(基于database/sql)和兼顾性能, 实现了轻量的 orm
2.因为工作中用的是 protobuf, 为了更好的适配查询结果, 最终默认按 json
为 orm 的 tag, 同时支持自定义
3.orm 详情, 希望大佬给 start
orm示例
// Man 以下代码都是以此为准
type Man struct {
Id int32 `json:"id,omitempty"`
Name string `json:"name,omitempty"`
Age int32 `json:"age,omitempty"`
Addr string `json:"addr,omitempty"`
}
新增
m := Man{
Name: "xue1234",
Age: 18,
Addr: "成都市",
}
rows, _ = NewTable(db).Insert(m).Exec()
t.Log(rows.LastInsertId())
修改
m := Man{
Name: "xue12",
Age: 20,
Addr: "测试",
}
rows, _ := NewTable(db).Update(m, "id=?", 7).Exec()
t.Log(rows.LastInsertId())
删除
m := Man{
Id: 9,
}
rows, _ := NewTable(db).Delete(m).Exec()
t.Log(rows.LastInsertId())
查询
1.支持对查询结果进行回调操作; 对查询的列结果进行反序列化操作
2.可以对结构体 tag 进行别名查询, 即 tag 名与数据库列名不一致的时候, 可以通过指定 tag 别名进行查询
3.其能够高效的处理单表 CURD, 其在查询方面的性能接近原生, 其中做几个性能对比: 原生 >= spellsql-orm > gorm
4.查询结果支持: struct/map/单字段, 数据库返回的 NULL 类型; 不需要处理, orm 会自行处理, 如果传入空类型值会报错(如: sql.NullString)
单结果集查询
var m Man
// 指定查询列
_ = NewTable(db).Select("name,age").From("man").Where("id=?", 1).FindOne(&m)
t.Log(m)
// 根据查询对象解析
_ = NewTable(db).SelectAuto(m).Where("id=?", 1).FindOne(&m)
t.Log(m)
// 对查询结果进行内容修改
_ = NewTable(db).SelectAuto(m).Where("id=?", 1).FindOneFn(&m, func(_row interface{}) error {
v := _row.(*Man)
v.Name = "被修改了哦"
v.Age = 100000
return nil
})
t.Log(m)
// 基准测试, 以下是在 mac11 pro m1 上测试
func BenchmarkFindOneGorm(b *testing.B) {
b.ResetTimer()
for i := 0; i < b.N; i++ {
var m Man
gdb.Table("man").Find(&m, "id=?", 1)
}
// BenchmarkFindOneGorm-8 16958 66604 ns/op 4364 B/op 78 allocs/op
// BenchmarkFindOneGorm-8 18019 66307 ns/op 4365 B/op 78 allocs/op
// BenchmarkFindOneGorm-8 17989 66318 ns/op 4365 B/op 78 allocs/op
// BenchmarkFindOneGorm-8 18040 66146 ns/op 4365 B/op 78 allocs/op
// BenchmarkFindOneGorm-8 18103 66284 ns/op 4365 B/op 78 allocs/op
}
func BenchmarkFindOneQueryRowScan(b *testing.B) {
b.ResetTimer()
for i := 0; i < b.N; i++ {
var m Man
sqlStr := FmtSqlStr("SELECT name,age,addr FROM man WHERE id=?", 1)
_ = db.QueryRow(sqlStr).Scan(&m.Id, &m.Age, &m.Addr)
}
// BenchmarkFindOneQueryRowScan-8 32281 37144 ns/op 1187 B/op 29 allocs/op
// BenchmarkFindOneQueryRowScan-8 32155 37214 ns/op 1187 B/op 29 allocs/op
// BenchmarkFindOneQueryRowScan-8 32061 37085 ns/op 1187 B/op 29 allocs/op
// BenchmarkFindOneQueryRowScan-8 32131 37132 ns/op 1187 B/op 29 allocs/op
// BenchmarkFindOneQueryRowScan-8 32160 37183 ns/op 1187 B/op 29 allocs/op
}
func BenchmarkFindOneOrm(b *testing.B) {
b.ResetTimer()
for i := 0; i < b.N; i++ {
var m Man
_ = NewTable(db, "man").IsPrintSql(false).Select("name,age,addr").Where("id=?", 1).FindOne(&m)
}
// BenchmarkFindOneOrm-8 31676 38230 ns/op 1329 B/op 32 allocs/op
// BenchmarkFindOneOrm-8 31736 37573 ns/op 1329 B/op 32 allocs/op
// BenchmarkFindOneOrm-8 31701 37737 ns/op 1329 B/op 32 allocs/op
// BenchmarkFindOneOrm-8 31719 37599 ns/op 1329 B/op 32 allocs/op
// BenchmarkFindOneOrm-8 31854 37576 ns/op 1329 B/op 32 allocs/op
}
多结果集查询
var m []*Man
// 多结果查询
err := NewTable(db, "man").Select("id,name,age,addr").Where("id>?", 1).FindAll(&m)
if err != nil {
t.Fatal(err)
}
t.Logf("%+v", m)
// 对结果集进行处理
err := NewTable(db, "man").Select("id,name,age,addr").Where("id>?", 1).FindAll(&m, func(_row interface{}) error {
v := _row.(*Man)
if v.Id == 5 {
v.Name = "test"
}
fmt.Println(v.Id, v.Name, v.Age)
return nil
})
if err != nil {
t.Fatal(err)
}
t.Logf("%+v", m)
// 基准测试, 以下是在 mac11 pro m1 上测试
func BenchmarkFindAllGorm(b *testing.B) {
b.ResetTimer()
for i := 0; i < b.N; i++ {
var m []*Man
// sqlStr := FmtSqlStr("SELECT * FROM man WHERE id>?", 1)
gdb.Table("man").Limit(10).Find(&m, "id>?", 1)
// b.Log(m)
}
// BenchmarkFindAllGorm-8 11581 92114 ns/op 8962 B/op 273 allocs/op
// BenchmarkFindAllGorm-8 12896 91718 ns/op 8962 B/op 273 allocs/op
// BenchmarkFindAllGorm-8 12811 91760 ns/op 8961 B/op 273 allocs/op
// BenchmarkFindAllGorm-8 13072 91517 ns/op 8962 B/op 273 allocs/op
// BenchmarkFindAllGorm-8 13081 91715 ns/op 8962 B/op 273 allocs/op
}
func BenchmarkFindAllQuery(b *testing.B) {
b.ResetTimer()
for i := 0; i < b.N; i++ {
sqlStr := FmtSqlStr("SELECT name,age,addr FROM man WHERE id>? LIMIT ?, ?", 1, 0, 10)
rows, err := db.Query(sqlStr)
if err != nil {
return
}
var res []*Man
for rows.Next() {
var info Man
var addr sql.NullString
err = rows.Scan(&info.Name, &info.Age, &addr)
if err != nil {
continue
}
info.Addr = addr.String
res = append(res, &info)
}
rows.Close()
}
// BenchmarkFindAllQuery-8 23402 51492 ns/op 2769 B/op 99 allocs/op
// BenchmarkFindAllQuery-8 23434 51465 ns/op 2769 B/op 99 allocs/op
// BenchmarkFindAllQuery-8 22744 52913 ns/op 2769 B/op 99 allocs/op
// BenchmarkFindAllQuery-8 23089 51675 ns/op 2769 B/op 99 allocs/op
// BenchmarkFindAllQuery-8 23162 51550 ns/op 2768 B/op 99 allocs/op
}
func BenchmarkFindAllOrm(b *testing.B) {
b.ResetTimer()
for i := 0; i < b.N; i++ {
var m []*Man
_ = NewTable(db).IsPrintSql(false).Select("name,age,addr").From("man").Where("id>?", 1).Limit(0, 10).FindAll(&m)
}
// BenchmarkFindAllOrm-8 21327 57296 ns/op 3235 B/op 115 allocs/op
// BenchmarkFindAllOrm-8 21588 55743 ns/op 3235 B/op 115 allocs/op
// BenchmarkFindAllOrm-8 21538 55733 ns/op 3235 B/op 115 allocs/op
// BenchmarkFindAllOrm-8 21524 56888 ns/op 3235 B/op 115 allocs/op
// BenchmarkFindAllOrm-8 21366 55844 ns/op 3235 B/op 115 allocs/op
}