This is a creation in Article, where the information may have evolved or changed.
Xorm
Xorm is a Go language ORM library. It makes it easy to operate the database.
All document points I
Introduction to Usage:
Premise: Define the struct and codebase used in this article as follows
// 银行账户type Account struct { Id int64 Name string `xorm:"unique"` Balance float64 Version int `xorm:"version"` // 乐观锁}var x *xorm.Engine
- Creating an ORM Engine
Note: If you want to work with MySQL, you need to load the MySQL driver in such a way
import _ "github.com/go-sql-driver/mysql"
x,err:=xorm.NewEngine("mysql", "root:111111@/sys?charset=utf8")
- Automatic synchronization of Table structures
if err = x.Sync2(new(Account)); err != nil { log.Fatalf("Fail to sync database: %v\n", err) }
SYNC2 will do the following:
- Automatically detect and create tables, this detection is based on the name of the table
- Automatically detects and adds fields from the table, which is based on the field name and gives warning messages to the extra fields in the table
- Automatic detection, creation and deletion of indexes and unique indexes, this detection is based on the index of one or more field names, not on the index name. It is therefore important to note that if a new index is introduced into a table with a large amount of data, the database may take some time to index.
- Automatic conversion of the varchar field type to the Text field type automatically warns of inconsistencies between the model and the database for other field types.
- The default value of the Automatic warning field, whether the empty information does not match between the model and the database
These warning messages need to be engine.ShowWarn
set to be true
displayed.
- Adding and removing changes operation
* * Add action: Insert a new record, the record must not exist, or an error will be returned:
**
_, err := x.Insert(&Account{Name: name, Balance: balance})
Delete operation:
_, err := x.Delete(&Account{Id: id})
After the method delete takes the parameter, it is automatically searched based on the value passed in and then deleted. For example, if we specify the ID field of the account, we delete the record with the same ID field value as we assigned, and if you only assign a value to the Name field, then Xorm will find the record with the Name field value matching. If multiple fields are assigned at the same time, the records that are met by multiple criteria are deleted.
There are no restrictions on the objects that are targeted by the delete operation, which are deleted (individually and in bulk) if the condition is found.
Get and modify records: The records you want to modify must be pre-existing, so you need to query the records you want to modify before you modify them.
Get Records:
Get method
Querying a single data using the Get method requires that a pointer to the struct be passed in when the Get method is called, while the non-null field in the struct automatically becomes the query's condition and the preceding method condition is combined with the query.
A. Get a single piece of data based on the ID:
a:=&Account{}has, err := x.Id(id).Get(a)
B. Obtaining a single piece of data based on where
a := new(Account)has, err := x.Where("name=?", "adn").Get(a)
C. Obtaining a single data based on non-empty data present in the account structure
a := &Account{Id:1}has, err := x.Get(a)
The returned result is two parameters, one has (bool type) is present for the record, and the second argument is err for error. Whether or not err is nil,has, it is possible to be true or false.
After we get to the record, we need to make some changes and then update to the database:
a.Balance += deposit// 对已有记录进行更新_, err = x.Update(a)
Note that the parameter that is accepted by update is a pointer
Get information in bulk
err = x.Desc("balance").Find(&as)
Here, we also call the Desc method to sort the accounts from large to small according to the deposit amount.
The first parameter of the Find method is a pointer to slice or a map pointer, which is the result returned after the query, and the second parameter is optional, as a pointer to the conditional struct of the query.
- Optimistic lock
Optimistic locking is a more practical feature provided by Xorm, which is opened by specifying version in tag. Once turned on, the value of the field is automatically incremented by 1 each time the record is updated. As a result, you can determine if there are other places that have modified the record at the same time, and if so, you should re-operate it, otherwise the wrong data will appear (and the amount that you have withdrawn from an account is deducted only once).
Transactions and rollbacks
Nonsense not much to say, directly on the example code:
// 创建 Session 对象sess := x.NewSession()defer sess.Close()// 开启事务if err = sess.Begin(); err != nil { return err}if _, err = sess.Update(a1); err != nil { // 发生错误时进行回滚 sess.Rollback() return err} // 完成事务return sess.Commit()
Statistics record Bars-count method
Statistics using the Count method, the parameter of the Count method is a pointer to a struct and becomes a query condition.
a := new(Account)//返回满足id>1的Account的记录条数total, err := x.Where("id >?", 1).Count(a)//返回Account所有记录条数total,err = x.Count(a)
Iterate method
The iterate method provides a way to execute a query-by-article method, and he can use exactly the same conditions as the Find method
err := x.Where("id > ?=)", 30).Iterate(new(Account), func(i int, bean interface{})error{ user := bean.(*Account) //do somthing use i and user})
Querying specific fields
We mainly look at the declaration of the iterative function: it accepts 2 parameters, the first is the index of the current record (the index and the value of the ID is irrelevant, only the index of the result after the query), the second parameter is to save the relevant type of NULL interface, you need to assert themselves, such as the use of beans in the example. (*account) because we know the structure of the query is account.
Querying specific fields
You can use the Cols method to specify a query-specific field that can be used when only the value of a field in the structure is valuable to you:
x.Cols("name").Iterate(new(Account), printFn)var printFn = func(idx int, bean interface{}) error { //dosomething return nil}
Here, the queried structure only has a value for the Name field, and the other fields are zero values. Note that the parameters that the Cols method accepts are the corresponding names in the data table, not the field names.
Exclude specific fields
When you want to deliberately ignore query results for a field, you can use the Omit method:
X.omit ("name"). Iterate (new account, PRINTFN)
Here, the queried structure is only a zero value for the Name field. Note that the parameters that the Omit method accepts are the corresponding names in the data table, not the field names.
Query result offset
The query result offset is most common in paging applications and can be achieved in the same way through the Limit method:
x.Limit(3, 2).Iterate(new(Account), printFn)
The method accepts a minimum of 1 parameters, the first parameter indicates the maximum number of records fetched, or, if passed in the second argument, offsets the result of the query. Therefore, the query result here is offset by 2, and then up to 3 records are removed.
Log records
In general, x.ShowSQL = true
all SQL will be printed to the console using the Xorm most basic logging function, but if you want to save the log to a file, you can do the following after obtaining the ORM engine:
f, err := os.Create("sql.log")if err != nil { log.Fatalf("Fail to create log file: %v\n", err) return}x.Logger = xorm.NewSimpleLogger(f)
LRU Cache
As the only ORM that supports LRU caching, it would be a pity if you don't know how to use this feature. However, it is not difficult to use it, just after acquiring the ORM engine, do the following:
cacher := xorm.NewLRUCacher(xorm.NewMemoryStore(), 1000)x.SetDefaultCacher(cacher)
This is the use of the most basic caching capabilities. The feature also supports caching only certain tables or excluding certain tables, as detailed in the official documentation for the article header.
Event Hooks
The official offers a total of 6 types of event hooks, only 2 of which are shown in the example: BeforeInsert and AfterInsert. View full Article Header official documents
Their effects are called before the insert record is made and after the insert record is completed:
Func (a *account) BeforeInsert () {
Log. Printf ("Before insert:%s", A.name)
}
Func (a *account) AfterInsert () {
Log. Printf ("After insert:%s", A.name)
}
Here is a simple example of a bank deposit and withdrawal
Package Mainimport ("Errors" "Log" "Github.com/go-xorm/xorm" _ "Github.com/mattn/go-sqlite3")//bank Account type Acco unt struct {Id int64 Name string ' xorm: ' Unique ' ' Balance float64 Version int ' xorm: ' Version ' '//Optimistic lock} ORM engine var x *xorm. Enginefunc init () {//create ORM engine with database var err x, err = Xorm. Newengine ("MySQL", "Root:111111@/sys?charset=utf8") if err! = Nil {log. Fatalf ("Fail to create Engine:%v\n", err)}//Synchronize structure with data table if Err = X.sync (new account); Err! = Nil {log. Fatalf ("Fail to sync Database:%v\n", err)}}//Create new account func NewAccount (name string, balance float64) error {//for non-existent The record is inserted _, Err: = X.insert (&account{name:name, balance:balance}) return err}//get account information func Getaccount (ID Int64) ( *account, error) {A: = &account{}//Direct operation ID is an easy way to have, err: = X.id (ID). Get (a)//determine if the operation has an error or if the object exists if err! = Nil {return nil, err} else if!has {return nil, errors. New ("AccOunt does not exist ")} return a, nil}//user transfer func Maketransfer (ID1, id2 Int64, balance float64) Error {//create Ses Sion object Sess: = X.newsession () defer sess. Close ()//start transaction if Err = Sess. Begin (); Err! = Nil {return err} a1, err: = Getaccount (ID1) if err! = Nil {return err} a2, err: = Getaccount (ID2) if err! = Nil {return err} if A1. Balance < Balance {return errors. New ("Not Enough Balance")} A1. Balance-= Balance A2. Balance + = Balance if _, err = Sess. Update (A1); Err! = Nil {//rollback sess When an error occurs. Rollback () Return Err} If _, err = Sess. Update (A2); Err! = Nil {Sess. Rollback () return err}//Complete transaction return Sess. Commit () return nil}//user deposit Func makedeposit (id int64, deposit float64) (*account, error) {A, err: = Getaccount (ID) If err! = Nil {return nil, err} sess: = X.newsession () defer sess. Close () If Err = Sess. Begin ();Err! = Nil {return nil, err} a.balance + = deposit//Update an existing record if _, err = Sess. Update (a); Err! = Nil {Sess. Rollback () return nil, err} return a, Sess. Commit ()}//User withdrawal func Makewithdraw (id int64, withdraw float64) (*account, error) {A, err: = Getaccount (ID) if err! = Nil {return nil, err} if a.balance < withdraw {return nil, errors. New ("Not Enough Balance")} Sess: = X.newsession () defer sess. Close () If _, err = Sess. Begin (); Err! = Nil {return nil, err} a.balance-= Withdraw if _, err = Sess. Update (a); Err! = Nil {return nil, err} return a, Sess. Commit ()}//returns all accounts in a positive order by ID Func Getaccountsascid () (as []account, err Error) {//Use the Find method to fetch records in bulk err = X.find (&am P;as) return as, err}//returns all accounts in reverse order of deposit Func getaccountsdescbalance () (as []account, err Error) {//using the Desc method to reverse the results Order err = X.desc ("balance"). Find (&as) return as, err}//Delete account func DeleteaccoUNT (ID Int64) error {//delete record with Delete method _, Err: = X.delete (&account{id:id}) return err}
Note: This article references
- Go Name Library explanation
- Official documents