An easy ORM tool for Golang, support MyBatis-Like XML template SQL
-
对象继承
的 实现 -
延 迟加载或加 密 字 段 (或 特殊 处理)的 实现有 泛型了 ,可 以尝试下type Lazy[T any] struct { value T session SqlSession sqlstr string } func (l *Lazy[T]) Read() T { session.Query() } //
加 密 字 段 (或 特殊 处理) type Passworder struct { value string } func (p *Passworder) Scan(interface{}) error { xxxxx } func (p *Passworder) Value() driver.Value { xxxxx } type Record struct { TableName struct{} `db:records` Blob Lazy[[]byte] `db:"blob"` Password Passworder `db:"password"` } -
返 回 大量 数 据 记录时用泛型来 改 进type Results[T any] struct {} func (rs *Results) Next() bool {} func (rs *Results) Read(value *T) error {}
-
当 sql中 含有 xml 标签时<
号 需要 转义为<
,而不含 xml 标签时<
又 不 转义为<
, 这很不一致 。最近 我 改 进了一 个像 mybatis一 样用 gt, gte,lt和 lte代替 >,>=, <和 <=, 如a > 8
写 成 a gt 8a >= 8
写 成 a gte 8a < 8
写 成 a lt 8a <= 8
写 成 a lte 8 -
达梦
数 据 库实现 upsert 时无法 返 回 insert id (达梦数 据 库的问题)。
GoBatis 就是对 MyBatis
我 实现一 个和 mybatis 类似的 if, chose, foreach, trim, set 和 where 之 类的 xml 基本 实现,同 时也支持 go template 来 生成 sql。
当 inStr="true" 时我会 检查 value 的 值中是 不 是 有 引号之 类的字 符 ,防止 sql 注入
当 inStr="false" 时我会 检查 value 的 值中是 不 是 有 and 或 or 之 类的逻辑表 达式,防止 sql 注入
MyBatis
用 户定义结构和接 口 在 接 口 的 方法 上 定 义 sql (可 以在 xml中 或 方法 的 注 释中)用 工具 生成 接 口 的 实现- 创建
接 口 的 实例并使用 它
升 级 go1.14后 goparser特 别慢,准 备用 goparser2替 换将 xml相 关代码移到 xml子 目 录将 sql生成 工具 builder相 关代码移到 sql子 目 录
-
install
gobatis
tools.go get -u -v github.com/runner-mei/GoBatis/cmd/gobatis
-
Define a struct, interface and comment methods with SQLs and Variables, then write a directive
//go:generate gobatis user.go
.
//go:generate gobatis user.go
package example
import (
"time"
)
type AuthUser struct {
ID int64 `json:"id"`
Username string `json:"username"`
Phone string `json:"phone"`
Address *string `json:"address"`
Status uint8 `json:"status"`
BirthDay *time.Time `json:"birth_day"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
}
type UserDao interface {
// @postgres insert into auth_users(username, phone, address, status, birth_day, created_at, updated_at)
// values (#{username},#{phone},#{address},#{status},#{birth_day},CURRENT_TIMESTAMP, CURRENT_TIMESTAMP) returning id
//
// @default insert into auth_users(username, phone, address, status, birth_day, created_at, updated_at)
// values (#{username},#{phone},#{address},#{status},#{birth_day},CURRENT_TIMESTAMP, CURRENT_TIMESTAMP)
Insert(u *AuthUser) (int64, error)
}
- After that, run
go generate ./...
, user.gobatis.go is generated
// Please don't edit this file!
package example
import (
"errors"
gobatis "github.com/runner-mei/GoBatis"
)
func init() {
gobatis.Init(func(ctx *gobatis.InitContext) error {
{ //// UserDao.Insert
if _, exists := ctx.Statements["UserDao.Insert"]; !exists {
sqlStr := "insert into auth_users(username, phone, address, status, birth_day, created_at, updated_at)\r\n values (#{username},#{phone},#{address},#{status},#{birth_day},CURRENT_TIMESTAMP, CURRENT_TIMESTAMP)"
switch ctx.Dialect {
case gobatis.NewDialect("mssql"):
sqlStr = "insert into auth_users(username, phone, address, status, birth_day, created_at, updated_at)\r\n output inserted.id\r\n values (#{username},#{phone},#{address},#{status},#{birth_day},CURRENT_TIMESTAMP, CURRENT_TIMESTAMP)"
case gobatis.NewDialect("postgres"):
sqlStr = "insert into auth_users(username, phone, address, status, birth_day, created_at, updated_at)\r\n values (#{username},#{phone},#{address},#{status},#{birth_day},CURRENT_TIMESTAMP, CURRENT_TIMESTAMP) returning id"
}
stmt, err := gobatis.NewMapppedStatement(ctx, "UserDao.Insert",
gobatis.StatementTypeInsert,
gobatis.ResultStruct,
sqlStr)
if err != nil {
return err
}
ctx.Statements["UserDao.Insert"] = stmt
}
}
})
}
func NewUserDao(session gobatis.SqlSession) UserDao {
return &UserDaoImpl{session: session}
}
type UserDaoImpl struct {
session gobatis.SqlSession
}
func (impl *UserDaoImpl) Insert(u *AuthUser) (int64, error) {
return impl.session.Insert("UserDao.Insert",
[]string{
"u",
},
[]interface{}{
u,
})
}
...
- use UserDao
factory, err := gobatis.New(&gobatis.Config{DriverName: tests.TestDrv,
DataSource: tests.GetTestConnURL(),
// XMLPaths: []string{"example/test.xml"},
})
userDao := NewUserDao(factory.SessionReference())
id, err := userDao.Insert(&insertUser)
if err != nil {
fmt.Println(err)
return
}
fmt.Println("insert success!")
u, err := userDao.Get(id)
if err != nil {
fmt.Println(err)
return
}
fmt.Println("fetch user from database!")
_, err = userDao.Delete(id)
if err != nil {
fmt.Println(err)
return
}
fmt.Println("delete success!")
GoBatis