First article: Using Golang to encapsulate database standard operations (MySQL)
Background
Encapsulates database standard operations with Golang, providing a database access layer to the rest server behind. The goal is to automatically generate database operation statements according to rest request parameters, and provide the necessary database operation encapsulation such as increment, delete, change, check, batch write, transaction, etc. And can be easily extended to a variety of databases, so that all database operations for the rest server performance as a consistent provider.
Some key points
- Interface design is just right, enough and not complicated.
- function parameter design, go does not support function overloading, how to use interface{}.
- Use map[string]interface{} to process the JSON request parameters of rest and generate the corresponding SQL automatically.
- Database query results can be easily converted into JSON, allowing rest server to return to the user.
Code parsing
Description of core code by function module
Ibock.go
database standard operation interface definition, according to my practical experience, the following interface design has been able to support most of the database operations, including automatic curd based on the JSON parameters, handwritten SQL support, BULK INSERT (update) Heart and transactional operations.
type IBock interface{ //根据参数,自动完成数据库查询 Retrieve(params map[string]interface{}, args ...interface{}) map[string]interface{} //根据参数,自动完成数据库插入 Create(params map[string]interface{}, args ...interface{}) map[string]interface{} //根据参数,自动完成数据库更新(只支持单条) Update(params map[string]interface{}, args ...interface{}) map[string]interface{} //根据参数,自动完成数据库删除(只支持单条) Delete(params map[string]interface{}, args ...interface{}) map[string]interface{} //手写查询sql支持 QuerySql(sql string, values []interface{}, params map[string]interface{}) map[string]interface{} //手写非查询sql支持 ExecSql(sql string, values []interface{}) map[string]interface{} //批量插入或更新 InsertBatch(tablename string, els []interface{}) map[string]interface{} //事务支持 TransGo(objs map[string]interface{}) map[string]interface{}}
parameter Description
- The params, which corresponds to the rest server, receives the user data, which is transformed by the JSON object.
- Args, the goal of this parameter is to receive ID (Information ID), Fields (table field array), session (user session) of the three parameters, the original intention is to unify the interface function form, but also at the time of encoding less pass as the dot character nil
- Values, parameter list provided for SQL query parameterization
- Els, the set of data objects for each row of bulk inserts
- OBJS, transaction object Set
- Returns the mapping of the parameter to go, which is easily converted to JSON.
Bock.go
The
concrete implementation of the interface, this article is the realization of MySQL, temporarily only achieved the basic curd, the project will gradually improve.
We define the operands on a table. The function of the type Bock struct {table String}//parseargs function is to parse the variable parameters included in the args parameter, implemented in the following func (b *bock) Retrieve (params m ap[string]interface{}, args ... interface{}) map[string]interface{} {//query when we are generally only interested in querying which table fields _, field, _: = Parseargs (A RGS)//Call the specific query interface, the query interface will automatically implement the SQL query statement according to the input parameter params, support a variety of query definitions, such as: lks (Query the same content from multiple fonts), ORS (or query), ins (in query), such as return query (b. Table, params, fields)}func (b *bock) Create (params map[string]interface{}, args ... interface{}) map[string]interface{} {//new interface, generally will focus on the user ID _, _, Session: = Parseargs (args) UId: = session["userid"]. (string) params["u_id"] = uId//Invoke specific insertion interface return insert (b.table, params)}func (b *bock) Update (params map[string] interface{}, args ... interface{}) map[string]interface{} {//only supports single update, so ID must exist ID, _, _: = Parseargs (args) If Len ( ID) = = 0 {rs: = make (map[string]interface{}) rs["code"] = 301 rs["Err"] = "Id must is input." Return RS} return Update (b.table, params)}func (b*bock) Delete (params map[string]interface{}, args ... interface{}) map[string]interface{} {//Only single Delete is supported, so ID must exist ID, _, _: = Parseargs (args) If len (id) = = 0 {rs: = make (map[string]interface{}) rs["code"] = 301 rs["ER r "] =" Id must be input. " Return RS} return Delete (b.table, params)}
implementation of Parseargs function
func parseArgs(args []interface{}) (string, []string, map[string]interface{}) { //解析指定的参数 var id string //信息ID var fields []string //查询字段集 var session map[string]interface{} //用户session对象 for _, vs := range args { switch vs.(type) { case map[string]interface{}: //只接收指定类型 for k, v := range vs.(map[string]interface{}) { if k == "id" { id = v.(string) } if k == "fields" { fields = v.([]string) } if k == "session" { session = v.(map[string]interface{}) } } default: } } return id, fields, session //返回解析成功的参数}
Helper.go
data operation of the specific implementation, mostly pseudo-code, the project will be gradually improved, the query interface is the most important, there will be a separate article to parse
func Query(tablename string, params map[string]interface{}, fields []string ) map[string]interface{} { //调用具体实现的私用函数,接口中分自动和手动两个函数,在私用函数中屏蔽差异内聚功能 return query(tablename, params, fields, "", nil)}func Insert(tablename string, params map[string]interface{}) map[string]interface{} { sql := "Insert into " + tablename values := make([]interface{},0) return execute(sql, values)}func Update(tablename string, params map[string]interface{}) map[string]interface{} { sql := "Update " + tablename + " set " values := make([]interface{},0) return execute(sql, values)}func Delete(tablename string, params map[string]interface{}) map[string]interface{} { sql := "Delete from " + tablename + " where" values := make([]interface{},0) return execute(sql, values)}
private query function definition
//五个输入参数,分别适配自动与手动查询func query(tablename string, params map[string]interface{}, fields []string, sql string, vaules []interface{}) map[string]interface{} { if vaules == nil { vaules = make([]interface{},0) } //调用真正的数据库操作函数 return execQeury("select "+ strings.Join(fields, ",")+" from " + tablename, vaules)}
non-query class specific operation function
//因为golang把有结果集的和无结果集的操作是分开的,不象在java或node.js中,可以有高级函数进行统一操作,只能分开。func execute(sql string, values []interface{}) map[string]interface{} { //返回json对象,以map形式表达 rs := make(map[string]interface{}) rs["code"] = 200 return rs}
Query class specific operations (already implemented), result sets are encapsulated in JSON objects, stored in map
Func execqeury (SQL string, values []interface{}) map[string]interface{} {var configs interface{} ...//omit the data configuration to get the code, please Refer to the previous article DAO, err: = MySQL. Open (dialect, DbUser + ":" +dbpass+ "@tcp (" +dbhost+ ":" +dbport+ ")/" +dbname+ "? charset=" +dbcharset "stmt, err: = DAO. Prepare (SQL) rows, err: = stmt. Query (Values ...) Columns, err: = rows. Columns ()//Remove field name vs: = Make ([]mysql. Rawbytes, Len (columns)) Scans: = Make ([]interface{}, Len (columns)) for I: = Range vs {//preset value address Scans[i] = &vs[i]} var result []map[string]interface{} for rows. Next () {_ = rows. Scan (Scans ...) Required into a column value each: = Do (map[string]interface{}) for I, col: = Range vs {if Col! = Nil { Each[columns[i]] = string (col)//Value Added}else{each[columns[i]] = nil} } result = Append (result, each)} rs["code"] =//data, _: = json. Marshal (Result)//This isCan be converted to JSON rs["rows"] = result return RS}
database of bulk operations, in the previous article has been implemented with Golang, but not encapsulated, interested friends can see my previous article.
Bock.go (Program Entry)
The
final goal of the portal will be a Web service that provides standard restful services, now only for testing, and this illustrates the vision.
table := Bock.Bock{ //上体实例 Table: "role", //对role表时行操作 } var params map[string] interface{} //模拟json参数 args := make(map[string] interface{}) //其它参数 db := make([]DB.IBock, 1) //对接口编程 db[0] = &table //接口指向实例对象,这里可以现时处理多个不同的实例 fields := []string {"id", "name"} args["fields"] = fields rs, _ := db[0].Retrieve(params, args) //在这可以循环处理多个不同的实例,我们最终的目标就是在这接受用户的http请求,由路由自动分发不同的请求,我们的数据库封装自动生成sql语句完成用户的基本需求。 fmt.Println(rs)
Project Address
https://github.com/zhoutk/goTools
How to use
git clone https://github.com/zhoutk/goToolscd goToolsgo getgo run bock.gogo buid bock.go./bock
Summary
Through a variety of scenarios compared to find that the go language as a network service throughput is the best, so with the previous experience on other platforms (Node.js,java,python3), with go to achieve, expect surprises, write code I am serious.