Documentation ¶
Overview ¶
Package orm 一个简单小巧的 orm 实现方案。
目前内置了对以下数据库的支持:
- sqlite3: github.com/mattn/go-sqlite3
- mysql: github.com/go-sql-driver/mysql
- postgres: github.com/lib/pq
其它数据库,用户可以通过实现 Dialect 接口,来实现相应的支持。
初始化:
默认情况下,orm 包并不会加载任何数据库的实例。所以想要用哪个数据库,需要手动初始化:
import ( _ github.com/mattn/go-sqlite3 // 加载数据库驱动 _ github.com/issue9/orm/dialect // sqlite3 的 dialect 声明在此处 ) // 初始化一个 DB,表前缀为 prefix_ db1 := orm.NewDB("sqlite3", "./db1", "prefix_", dialect.Sqlite3()) // 另一个 DB 实例 db2 := orm.NewDB("sqlite3", "./db2", "db2_", dialect.Sqlite3())
占位符
SQL 语句可以使用 # 字符在语句中暂替真实的表名前缀,也可以使用 {} 包含一个关键字,使其它成为普通列名,如:
select * from #user where {group}=1
在实际执行时,相关的占位符就会被替换成与当前环境想容的实例,如在表名前缀为 p_, 数据库为 mysql 时,会被替换成以下语句,然后再执行:
select * from p_user where `group`=1
DB.Query(),DB.Exec(),DB.Prepare().DB.Where() 及 Tx 与之对应的函数都可以使用占位符。
Model 不能指定占位符,它们默认总会使用占位符,且无法取消。
Model:
orm 包通过 struct tag 来描述 model 在数据库中的结构。大概格式如下:
type User struct { Id int64 `orm:"name(id);ai;"` FirstName string `orm:"name(first_name);index(index_name)"` LastName string `orm:"name(first_name);index(index_name)"` // 此处group会自动加上引号,无须担心是否为关键字 Group string `orm:"name(group)"` } // 通过 orm.Metaer 接口,指定表的额外数据。若不需要,可不用实现该接口 // 表名 user 会被自动加上表名前缀。 func(u *User) Meta() string { return "name(user);engine(innodb);charset(utf-8)" }
目前支持以下的 struct tag:
name(fieldName): 将当前的字段映射到数据表中的 fieldName 字段。 len(l1, l2): 指定字段的长度。比如 mysql 中的int(5),varchar(255),double(1,2), 不支持该特性的数据,将会忽略该标签的内容,比如 sqlite3。 NOTE:字符串类型必须指定长度,若长度过大或是将长度设置了-1, 想使用类似于 TEXT 等不定长的形式表达。 nullable(true|false): 相当于定义表结构时的 NULL,建议尽量少用该属性, 若非用不可的话,与之对应的 Go 属性必须声明为 NullString之类的结构。 pk: 主键,支持联合主键,给多个字段加上pk的struct tag即可。 ai: 自增,若指定了自增列,则将自动取消其它的 pk 设置。无法指定起始值和步长。 可手动设置一个非零值来更改某条数据的 AI 行为。 unique(index_name): 唯一索引,支持联合索引,index_name 为约束名, 会将 index_name 为一样的字段定义为一个联合索引。 index(index_name): 普通的关键字索引,同 unique 一样会将名称相同的索引定义为一个联合索引。
occ(true|false) 当前列作为乐观锁字段。
default(value): 指定默认值。相当于定义表结构时的 DEFAULT。 当一个字段如果是个零值(reflect.Zero())时,将会使用它的默认值, 但是系统无法判断该零值是人为指定,还是未指定被默认初始化零值的, 所以在需要用到零值的字段,最好不要用 default 的 struct tag。 fk(fk_name,refTable,refColName,updateRule,deleteRule): 定义物理外键,最少需要指定 fk_name,refTabl,refColName 三个值。分别对应约束名, 引用的表和引用的字段,updateRule,deleteRule,在不指定的情况下,使用数据库的默认值。 check(chk_name, expr): check 约束。chk_name 为约束名,expr 为该约束的表达式。 check 约束只能在 model.Metaer 接口中指定,而不是像其它约束一样,通过字段的 struct tag 指定。 因为 check 约束的表达式可以通过 and 或是 or 等符号连接多条基本表达式, 在字段 struct tag 中指定会显得有点怪异。
model.Metaer:
在 Go 不能将 struct tag 作用于结构体,所以为了指定一些表级别的属性, 只能通过接口的形式,在接口方法中返回一段类似于 struct tag 的字符串, 以达到相同的目的。
在 model.Metaer 中除了可以指定 name(table_name) 和 check(name,expr) 两个属性之外, 还可指定一些自定义的属性,这些属性都将会被保存到 Model.Meta 中。
约束名:
index,unique,check,fk 都是可以指定约束名的,在表中,约束名必须是唯一的, 即便是不同类型的约束,比如已经有一个 unique 的约束名叫作 name,那么其它类 型的约束,就不能再取这个名称了。
如何使用:
Create: 可以通过 DB.Create() 或是 Tx.Create() 创建一张表。
// 创建表 db.Create(&User{}) // 创建多个表,同时创建多张表,主使用 Tx.Create tx.MultCreate(&User{},&Email{})
Update:
// 将 id 为 1 的记录的 FirstName 更改为 abc;对象中的零值不会被提交。 db.Update(&User{Id:1,FirstName:"abc"}) sqlbuilder.Update(db).Table("#table").Where("id=?",1).Set("FirstName", "abc").Exec()
Delete:
// 删除 id 为 1 的记录 e.Delete(&User{Id:1}) sqlbuilder.Delete(e).Table("#table").Where("id=?",1).Exec()
Insert:
// 插入一条数据 db.Insert(&User{Id:1,FirstName:"abc"}) // 一次性插入多条数据 tx.InsertMany(&User{Id:1,FirstName:"abc"},&User{Id:1,FirstName:"abc"})
Select:
// 导出 id=1 的数据 _,err := sqlbuilder.Select(e, e.Dialect()).Select("*").From("{#table}").Where("id=1").QueryObj(obj) // 导出 id 为 1 的数据,并回填到 user 实例中 user := &User{Id:1} err := e.Select(u)
Query/Exec:
// Query 返回参数与 sql.Query 是相同的 sql := "select * from #tbl_name where id=?" rows, err := e.Query(sql, []interface{}{5}) // Exec 返回参数与 sql.Exec 是相同的 sql = "update #tbl_name set name=? where id=?" r, err := e.Exec(sql, []interface{}{"name1", 5})
事务:
默认的 DB 是不支持事务的,若需要事务支持,则需要调用 DB.Begin() 返回事务对象 Tx,当然并不是所有的数据库都支持事务操作的。 Tx拥有一组与 DB 相同的接口,另外还提供了一组以 `Mult` 开头的函数, 用以同时操作多条记录的。
Index ¶
- func ClearModels()
- type AfterFetcher
- type BeforeInserter
- type BeforeUpdater
- type Column
- type DB
- func (db *DB) Begin() (*Tx, error)
- func (db *DB) Close() error
- func (db *DB) Count(v interface{}) (int64, error)
- func (db *DB) Create(v interface{}) error
- func (db *DB) Delete(v interface{}) (sql.Result, error)
- func (db *DB) Dialect() Dialect
- func (db *DB) Drop(v interface{}) error
- func (db *DB) Exec(query string, args ...interface{}) (sql.Result, error)
- func (db *DB) ExecContext(ctx context.Context, query string, args ...interface{}) (sql.Result, error)
- func (db *DB) Insert(v interface{}) (sql.Result, error)
- func (db *DB) LastInsertID(v interface{}) (int64, error)
- func (db *DB) MultCreate(objs ...interface{}) error
- func (db *DB) MultDelete(objs ...interface{}) error
- func (db *DB) MultDrop(objs ...interface{}) error
- func (db *DB) MultInsert(objs ...interface{}) error
- func (db *DB) MultSelect(objs ...interface{}) error
- func (db *DB) MultTruncate(objs ...interface{}) error
- func (db *DB) MultUpdate(objs ...interface{}) error
- func (db *DB) Prepare(query string) (*sql.Stmt, error)
- func (db *DB) PrepareContext(ctx context.Context, query string) (*sql.Stmt, error)
- func (db *DB) Query(query string, args ...interface{}) (*sql.Rows, error)
- func (db *DB) QueryContext(ctx context.Context, query string, args ...interface{}) (*sql.Rows, error)
- func (db *DB) QueryRow(query string, args ...interface{}) *sql.Row
- func (db *DB) QueryRowContext(ctx context.Context, query string, args ...interface{}) *sql.Row
- func (db *DB) SQL() *SQL
- func (db *DB) Select(v interface{}) error
- func (db *DB) StdDB() *sql.DB
- func (db *DB) Truncate(v interface{}) error
- func (db *DB) Update(v interface{}, cols ...string) (sql.Result, error)
- type Dialect
- type Engine
- type ForeignKey
- type Metaer
- type Model
- type SQL
- func (sql *SQL) CreateIndex() *sqlbuilder.CreateIndexStmt
- func (sql *SQL) Delete() *sqlbuilder.DeleteStmt
- func (sql *SQL) DropTable() *sqlbuilder.DropTableStmt
- func (sql *SQL) Insert() *sqlbuilder.InsertStmt
- func (sql *SQL) Select() *sqlbuilder.SelectStmt
- func (sql *SQL) Update() *sqlbuilder.UpdateStmt
- type Tx
- func (tx *Tx) Commit() error
- func (tx *Tx) Count(v interface{}) (int64, error)
- func (tx *Tx) Create(v interface{}) error
- func (tx *Tx) Delete(v interface{}) (sql.Result, error)
- func (tx *Tx) Dialect() Dialect
- func (tx *Tx) Drop(v interface{}) error
- func (tx *Tx) Exec(query string, args ...interface{}) (sql.Result, error)
- func (tx *Tx) ExecContext(ctx context.Context, query string, args ...interface{}) (sql.Result, error)
- func (tx *Tx) ForUpdate(v interface{}) error
- func (tx *Tx) Insert(v interface{}) (sql.Result, error)
- func (tx *Tx) InsertMany(v interface{}) error
- func (tx *Tx) LastInsertID(v interface{}) (int64, error)
- func (tx *Tx) MultCreate(objs ...interface{}) error
- func (tx *Tx) MultDelete(objs ...interface{}) error
- func (tx *Tx) MultDrop(objs ...interface{}) error
- func (tx *Tx) MultInsert(objs ...interface{}) error
- func (tx *Tx) MultSelect(objs ...interface{}) error
- func (tx *Tx) MultTruncate(objs ...interface{}) error
- func (tx *Tx) MultUpdate(objs ...interface{}) error
- func (tx *Tx) Prepare(query string) (*sql.Stmt, error)
- func (tx *Tx) PrepareContext(ctx context.Context, query string) (*sql.Stmt, error)
- func (tx *Tx) Query(query string, args ...interface{}) (*sql.Rows, error)
- func (tx *Tx) QueryContext(ctx context.Context, query string, args ...interface{}) (*sql.Rows, error)
- func (tx *Tx) QueryRow(query string, args ...interface{}) *sql.Row
- func (tx *Tx) QueryRowContext(ctx context.Context, query string, args ...interface{}) *sql.Row
- func (tx *Tx) Rollback() error
- func (tx *Tx) SQL() *SQL
- func (tx *Tx) Select(v interface{}) error
- func (tx *Tx) StdTx() *sql.Tx
- func (tx *Tx) Truncate(v interface{}) error
- func (tx *Tx) Update(v interface{}, cols ...string) (sql.Result, error)
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
Types ¶
type BeforeInserter ¶
type BeforeInserter interface {
BeforeInsert() error
}
BeforeInserter 在插入之前调用的函数
type Column ¶
type Column struct { Name string // 数据库的字段名 Len1 int // 长度1,仅对部分类型启作用 Len2 int // 长度2,仅对部分类型启作用 Nullable bool // 是否可以为 NULL GoType reflect.Type // Go 语言中的数据类型 GoName string // 结构字段名 HasDefault bool Default string // 默认值 // contains filtered or unexported fields }
Column 列结构
type DB ¶
type DB struct {
// contains filtered or unexported fields
}
DB 数据库操作实例。
func NewDBWithStdDB ¶
NewDBWithStdDB 从 sql.DB 构建一个 DB 实例。
func (*DB) Close ¶
Close 关闭当前数据库,释放所有的链接。
关闭之后,之前通过 DB.StdDB() 返回的实例也将失效。 通过调用 DB.StdDB().Close() 也将使当前实例失效。
func (*DB) ExecContext ¶
func (db *DB) ExecContext(ctx context.Context, query string, args ...interface{}) (sql.Result, error)
ExecContext 执行 SQL 语句。
func (*DB) LastInsertID ¶
LastInsertID 插入数据,并获取其自增的 ID。
func (*DB) MultSelect ¶
MultSelect 选择符合要求的一条或是多条记录。
func (*DB) MultTruncate ¶
MultTruncate 清除表内容,重置 ai,但保留表结构。
func (*DB) PrepareContext ¶
PrepareContext 预编译查询语句。
func (*DB) QueryContext ¶
func (db *DB) QueryContext(ctx context.Context, query string, args ...interface{}) (*sql.Rows, error)
QueryContext 执行一条查询语句,并返回相应的 sql.Rows 实例。
type Dialect ¶
type Dialect interface { sqlbuilder.Dialect // 返回符合当前数据库规范的引号对。 QuoteTuple() (openQuote, closeQuote byte) // 是否允许在事务中执行 DDL // // 比如在 postgresql 中,如果创建一个带索引的表,会采用在事务中, // 分多条语句创建表。 // 而像 mysql 等不支持事务内 DDL 的数据库,则会采用普通的方式, // 依次提交语句。 TransactionalDDL() bool // 根据当前的数据库,对 SQL 作调整。 // // 比如占位符 postgresql 可以使用 $1 等形式。 SQL(sql string) (string, error) // 清空表内容,重置 AI。 TruncateTableSQL(m *Model) []string // 生成创建表的 SQL 语句。 // // 创建表可能生成多条语句,比如创建表,以及相关的创建索引语句。 CreateTableSQL(m *Model) ([]string, error) }
Dialect 数据库驱动特有的语言特性实现
type Engine ¶
type Engine interface { sqlbuilder.Engine // 获取与之关联的 Dialect 接口。 Dialect() Dialect // 理论上功能等同于以下两步操作: // rslt,err := engine.Insert(obj) // id,err := rslt.LastInsertId() // 但是实际上部分数据库不支持直接在 sql.Result 中获取 LastInsertId, // 比如 postgresql,所以使用 LastInsertID() 会是比 sql.Result // 更简单和安全的方法。 // // NOTE: 要求 v 有定义自增列。 LastInsertID(v interface{}) (int64, error) Insert(v interface{}) (sql.Result, error) Delete(v interface{}) (sql.Result, error) Update(v interface{}, cols ...string) (sql.Result, error) Select(v interface{}) error Count(v interface{}) (int64, error) Create(v interface{}) error Drop(v interface{}) error Truncate(v interface{}) error MultInsert(objs ...interface{}) error MultSelect(objs ...interface{}) error MultUpdate(objs ...interface{}) error MultDelete(objs ...interface{}) error MultCreate(objs ...interface{}) error MultDrop(objs ...interface{}) error MultTruncate(objs ...interface{}) error SQL() *SQL }
Engine 是 DB 与 Tx 的共有接口。
type ForeignKey ¶
type ForeignKey struct { Col *Column RefTableName, RefColName string UpdateRule, DeleteRule string }
ForeignKey 外键
type Metaer ¶
type Metaer interface {
Meta() string
}
Metaer 用于指定一个表级别的元数据。如表名,存储引擎等:
"name(tbl_name);engine(myISAM);charset(utf-8)"
type Model ¶
type Model struct { Name string // 表的名称 Cols map[string]*Column // 所有的列 KeyIndexes map[string][]*Column // 索引列 UniqueIndexes map[string][]*Column // 唯一索引列 FK map[string]*ForeignKey // 外键 PK []*Column // 主键 AI *Column // 自增列 OCC *Column // 乐观锁 Check map[string]string // Check 键名为约束名,键值为约束表达式 Meta map[string][]string // 表级别的数据,如存储引擎,表名和字符集等。 // contains filtered or unexported fields }
Model 表示一个数据库的表模型。数据结构从字段和字段的 struct tag 中分析得出。
type SQL ¶
type SQL struct {
// contains filtered or unexported fields
}
SQL 用于生成 SQL 语句
func (*SQL) CreateIndex ¶
func (sql *SQL) CreateIndex() *sqlbuilder.CreateIndexStmt
CreateIndex 生成创建索引的语句
type Tx ¶
type Tx struct {
// contains filtered or unexported fields
}
Tx 事务对象
func (*Tx) ExecContext ¶
func (tx *Tx) ExecContext(ctx context.Context, query string, args ...interface{}) (sql.Result, error)
ExecContext 执行一条 SQL 语句。
func (*Tx) InsertMany ¶
InsertMany 插入多条相同的数据。若需要向某张表中插入多条记录, InsertMany() 会比 Insert() 性能上好很多。
与 MultInsert() 方法最大的不同在于:
// MultInsert() 可以每个参数的类型都不一样: vs := []interface{}{&user{...}, &userInfo{...}} db.Insert(vs...) // db.InsertMany(vs) // 这里将出错,数组的元素的类型必须相同。 us := []*users{&user{}, &user{}} db.InsertMany(us) db.Insert(us...) // 这样也行,但是性能会差好多
func (*Tx) LastInsertID ¶
LastInsertID 插入数据,并获取其自增的 ID。
func (*Tx) MultSelect ¶
MultSelect 选择符合要求的一条或是多条记录。
func (*Tx) MultTruncate ¶
MultTruncate 清除表内容,重置 ai,但保留表结构。
func (*Tx) PrepareContext ¶
PrepareContext 将一条 SQL 语句进行预编译。
func (*Tx) QueryContext ¶
func (tx *Tx) QueryContext(ctx context.Context, query string, args ...interface{}) (*sql.Rows, error)
QueryContext 执行一条查询语句。
Directories ¶
Path | Synopsis |
---|---|
Package dialect 提供了部分数据库对 orm.Dialect 接口的实现。
|
Package dialect 提供了部分数据库对 orm.Dialect 接口的实现。 |
Package fetch 包提供了将 sql.Rows 导出为几种常用数据格式的方法。
|
Package fetch 包提供了将 sql.Rows 导出为几种常用数据格式的方法。 |
internal
|
|
modeltest
Package modeltest 为 model 提供一些测试实例
|
Package modeltest 为 model 提供一些测试实例 |
sqltest
Package sqltest 提供对 SQL 内容测试的工具
|
Package sqltest 提供对 SQL 内容测试的工具 |
tags
Package tags 包实现对特定格式的 struct tag 字符串的分析。
|
Package tags 包实现对特定格式的 struct tag 字符串的分析。 |
Package sqlbuilder 提供一套通过字符串拼接来构成 SQL 语句的工具。
|
Package sqlbuilder 提供一套通过字符串拼接来构成 SQL 语句的工具。 |