SORM 操作框架,是一款适配国产化数据库操作的golang orm 框架,内部适配分库分表策略,提供类似于GORM的操作形式。内部包含所有数据库驱动,直接使用原生的驱动构建而成,提供一站式数据托管的数据操作能力。 欢迎对数据库感兴趣的小伙伴一起来改进这个库,毕竟以我自己一个人的力量还是微小,很多不足之处,欢迎给我留言。 [TOC]
目前支持的数据库驱动如下:
- dm 达梦
- gobase
- kingbase
- mysql
- opengauss
- oracle
- postgres
- shentong
- sqlite
- yxres 优炫
- odbc 驱动
后期改进
- 神通和达梦的数据库 大小写还是很反人类,设置大小写敏感,使用小写自动转成大写了,如果想使用小写需要使用"" 括起来处理,但是sql 又比较灵活,还有很多聚合和统计的函数不能一一实现,索性就让这两个数据库都使用大写的表名和字段去处理
- 关于数据库的自增,目前只支持字段自增,不能使用sequence,因为要同时兼容很多数据库,需要适配,这是也是一个坑。
- 还有一些数据库方言类的数据格式需要适配,可能需要一些细微的调整
数据库分库分表功能:
表指定数据库
// 单独给一个表存放一个数据库:
// cofnig 是数据库的配置文件
engine.AddDB("user", &conf)
分表策略
// TableName:表名
// TableShardType 分表策略
// TableSegName 表中分表的字段
engine.AddSpliter( spliter.Split{TableName: tableName, TableShardType: shardType, TableSegName: segName})
取模
%5:按照取模来分表,user_0、user_1,user_2、user_3,user_4 按照分表字段的对应的值 取模上面的数字,例如表名,user,分表的字段是age,按照分表策略%2,生成的表名就是user_0、user_1
m:按照月来分表 对应的表名为user_202001,user_202002,user_202003... d:按照天来分表 对应的表名为,user_20200101,user_20200102,user_20200103... w:按照周来分表 对应的表名为user_202028,user_202029,user_202030,... h:按照小时来分表 对应的表为user_2020010101 y:按照年来分表 对应的表名为user_2020,user_2021,user_2022,user_2023,...
数据库操作
初始化数据库引擎
conf := server.Config{ // 初始化一个engine
Type: "dm",
Host: "192.168.81.36",
Port: 5236,
Username: "test",
Password: "123456",
Database: "test",
}
engine, err := NewEngineWithConfig(&conf)
if err != nil {
t.Fatal("failed to connect", err)
}
定义数据表结构
type User struct {
Name string `column:"name" sorm:"PRIMARY KEY"`
Age int `json:"age" form:"age" column:"age"`
CreateTime time.Time `json:"create_time" form:"create_time" column:"create_time"`
Num *int `json:"num" form:"num" column:"num"`
}
func (u *User) GetTableName() string {
return "user"
}
上述代码定义了一个名为 User 的结构体,它对应数据库中的 user 表。结构体字段使用 column 标签指定了对应的数据库列名。 目前仅支持自增主键,使用 sorm:"PRIMARY KEY" 来表示,还未启用各个数据库的sequence,这个功能还没想好怎么加。
事务
事务框架会自动代理所有的数据库,提供整体的事务处理 使用数据库引擎的 Transaction 方法可以进行数据库事务操作。示例如下:
engine.Transaction(func(s *session.Session) (result interface{}, err error) {
s.Where("name =?", "John").First(&User{}) // find a user with name "John"")
}
创建数据:
使用数据库引擎的 Create 方法可以向数据库中插入数据。示例如下:
func create(t *testing.T) {
engine := OpenDB(t)
defer engine.Close()
u1 := User{Name: "Tom", CreateTime: time.Now()}
us := []User{
{Name: "Tom", Age: 18, CreateTime: t1, Num: n1},
{Name: "liu", Age: 19, CreateTime: t1, Num: n1},
{Name: "lao", Age: 20, CreateTime: time.Now()},
{Name: "ban", Age: 21, CreateTime: time.Now()},
}
s := engine.NewSession()
_, err := s.Create(&us)
if err != nil {
log.Infof("err:%+v\n", err)
return
}
_, err = s.Create(&u1)
if err != nil {
log.Infof("err:%+v\n", err)
return
}
_, err = s.Select("name", "age").Create(&u1)
if err != nil {
log.Infof("err:%+v\n", err)
return
}
_, err = s.Select("name", "age").Create(&us)
if err != nil {
log.Infof("err:%+v\n", err)
return
}
}
上述代码通过调用 engine.NewSession 创建一个数据库会话,然后使用会话的 Create 方法插入数据。可以一次插入多个数据,传入的参数为对应的结构体和切片。
查询数据
查询数据可选的方法就就比较多了
Select("name", "age") // 选择指定的字段
Omit("name") // 选择不显示指定的字段
Join(LEFT, "a", "a.id=b.id") // join 类型/表/连接条件
Limit(10)
Offset(10)
OrderBy("name desc") // order by
GroupBy("name") // group by
Having
var ps []Point
err := s.Model(&Point{}).Select("t19").Find(&ps)
if err != nil {
panic(err)
}
fmt.Println("ps:", ps)
更新数据
func UpdatePoint(t *testing.T) {
engine := OpenDB(t)
defer engine.Close()
//engine.AddUserSplitter()
s := engine.NewSession()
_, err := s.Model(&Point{}).Where("num = ?", 1).Update("t19 = ?", time.Now())
if err != nil {
panic(err)
}
}
删除数据
func deletePointTran(t *testing.T) {
engine := OpenDB(t)
defer engine.Close()
engine.AddUserSplitter()
engine.Transaction(func(s *session.Session) (interface{}, error) {
_, err := s.Model(&Point{}).Where("num = ? and name = ?", 4, "liu").Delete()
if err != nil {
panic(err)
}
return nil, nil
})
}