golang實現rest server架構(二)

來源:互聯網
上載者:User

第二篇:golang資料庫增刪改操作具體實現(mysql)

背景

這篇文章是golang針對資料庫增刪改(非查詢結果集,查詢語句的自動產生比較複雜,下篇文章專門解析)操作具體實現,包括了自動產生sql與自訂sql相關函數,以及指的插入與更新,同時實現了異常處理。

一些關鍵點

  1. 利用panic與recover實現資料庫異常處理。
  2. 函數可變參數的解析。
  3. 批量插入與更新使用同一個函數。
  4. 所有更新sql語句參數化。

代碼解析

按功能模組對核心代碼進行說明

異常處理

golang語言沒有異常處理,但可以通過panic、recover及defer來實現,值得注意的一點是,如何在defer中返回相應的資訊給上層函數。
                                              //rs要在這定義,defer中修改rs的資訊才能返回到上層調用函數func execute(sql string, values []interface{}) (rs map[string]interface{}) {    log.Println(sql, values)    rs = make(map[string]interface{})        //我原本rs是在這聲明並定義的,結果返回為空白    defer func() {        if r := recover(); r != nil {            rs["code"] = 500                //仔細想來,兩個返迴路徑,一個是正常return,一個是聲明中的rs傳回值            rs["err"] = "Exception, " + r.(error).Error()        }    }()    ...    //這其中的代碼若引發了panic,在返回上層調用函數前會執行defer    ...    return rs}

非查詢操作的底層封裝函數(execute)

golang的資料庫操作分返回查詢結果集的和無查詢結果集的,沒找到能統一處理的API,象java、node.js一樣,我只能分開封裝了,這裡實現execute。
func execute(sql string, values []interface{}) (rs map[string]interface{}) {    log.Println(sql, values)    ...    //異常處理與資料設定檔讀取    ...    //串連資料庫    dao, err := mysql.Open(dialect, dbUser+":"+dbPass+"@tcp("+dbHost+":"+dbPort+")/"+dbName+"?charset="+dbCharset)    stmt, _ := dao.Prepare(sql)        //預先處理    ers, err := stmt.Exec(values...)   //提供參數並執行    if err != nil {        rs["code"] = 204                //錯誤處理        rs["err"] = err.Error()    } else {        id, _ := ers.LastInsertId()        //自動成長ID的最新值,若插入        affect, _ := ers.RowsAffected()    //影響的行數        rs["code"] = 200        rs["info"] = sql[0:6] + " operation success."        rs["LastInsertId"] = id        rs["RowsAffected"] = affect    }    return rs                         //成功返回}
參數說明:
  • sql,調用這個函數時,要麼已經自動產生了標準的sql,要麼就自訂的sql,所有的語句要求是參數化形式的
  • values,參數列表,與sql中的預留位置一一對應

新增函數的實現(Insert)

資料新增操作的具體實現,這個是根據使用者提交的json資料自動產生標準sql的函數。
func Insert(tablename string, params map[string]interface{}) map[string]interface{} {    values := make([]interface{}, 0)    sql := "INSERT INTO `" + tablename + "` (" //+strings.Join(allFields, ",")+") VALUES ("    var ks []string    var vs []string    for k, v := range params {            //注意:golang中對象的遍曆,欄位的排列是隨機的        ks = append(ks, "`" + k + "`")    //儲存所有欄位        vs = append(vs, "?")              //提供相應的預留位置        values = append(values, v)        //對應儲存相應的值    }    //產生正常的插入語句    sql += strings.Join(ks, ",") + ") VALUES (" + strings.Join(vs, ",") + ")"    return execute(sql, values)}

修改函數的實現(Update)

資料修改操作的具體實現,這個是根據使用者提交的json資料自動產生標準sql的函數。
func Update(tablename string, params map[string]interface{}, id string) map[string]interface{} {    values := make([]interface{}, 0)    sql := "UPDATE `" + tablename + "` set " //+strings.Join(allFields, ",")+") VALUES ("    var ks string    index := 0    psLen := len(params)    for k, v := range params {        //遍曆對象        index++        values = append(values, v)    //參數        ks += "`" + k + "` =  ?"      //修改一個key的語句        if index < psLen {            //非最後一個key,加逗號            ks += ","        }    }    values = append(values, id)      //主鍵ID是單獨的    sql += ks + " WHERE id = ? "    return execute(sql, values)}

刪除函數的實現(Delete)

資料刪除操作的具體實現。
func Delete(tablename string, id string) map[string]interface{} {    sql := "DELETE FROM " + tablename + " where id = ? "        //只支援單個ID操作,這是自動化的介面,大量操作走其它介面    values := make([]interface{}, 0)    values = append(values, id)    return execute(sql, values)}

批量新增與修改函數的實現(InsertBatch)

資料批量新增與修改操作的具體實現,兩種方式在同一介面中實現。
func InsertBatch(tablename string, els []map[string]interface{}) map[string]interface{}  {    values := make([]interface{}, 0)    sql := "INSERT INTO " + tablename    var upStr string    var firstEl map[string]interface{}        //第一個插入或修改的對象    lenEls := len(els)                        //因為golang對象遍曆的隨機性,我們取出第一個對象先分析,去除隨機性    if lenEls > 0 {        firstEl = els[0]    }else {                                  //一個元素都沒有,顯然調用參數不對        rs := make(map[string]interface{})        rs["code"] = 301        rs["err"] = "Params is wrong, element must not be empty."        return rs    }    var allKey []string                      //儲存一個對象的所有欄位,對象訪問時就按這個順序    eleHolder := "("    index := 0    psLen := len(firstEl)    for k, v := range firstEl {        index++        eleHolder += "?"                          //預留位置        upStr += k + " = values (" + k + ")"      //更新操作時的欄位與值對應關係        if index < psLen {                        //非最後一個key            eleHolder += ","            upStr += ","        }else{            eleHolder += ")"        }        allKey = append(allKey, k)               //key        values = append(values, v)               //value    }    //大量操作的第一個對象語句的自動產生    sql += " ("+strings.Join(allKey, ",")+") values " + eleHolder    for i := 1; i < lenEls; i++ {             //依據對第一個對象的分析,產生所有的後續對象        sql += "," + eleHolder        for _, key := range allKey {            values = append(values, els[i][key])        }    }    //當主鍵或唯一索引存在時,進行更新操作的sql語句產生    sql += " ON DUPLICATE KEY UPDATE " + upStr    return execute(sql, values)}

bock.go(程式入口)

這裡提供一些用於測試的代碼。

用於測試的資料表結構

CREATE TABLE `books` (  `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '唯一性索引',  `name` varchar(64) DEFAULT '' COMMENT '名稱',  `isbn` varchar(64) DEFAULT '' COMMENT '圖書ISBN',  `u_id` int(11) DEFAULT '0' COMMENT '使用者ID',  `status` tinyint(4) DEFAULT '1' COMMENT '狀態:0-禁;1-有效;9刪除',  `create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '建立時間',  `update_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新時間',  PRIMARY KEY (`id`),  UNIQUE KEY `uuid` (`id`) USING BTREE) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COMMENT='表';

新增測試

    params := make(map[string] interface{})    args := make(map[string] interface{})    session := make(map[string] interface{})    session["userid"] = "112"    args["session"] = session    params["name"] = "golang實戰"    params["isbn"] = "41563qtrs5-X"    params["status"] = 1    db := &table    rs := db.Create(params, args)    fmt.Println(rs)

修改測試

    params = make(map[string] interface{})    args = make(map[string] interface{})    args["id"] = 2    params["name"] = "golang實戰,修改了"    params["status"] = 3    rs = db.Update(params, args)    fmt.Println(rs)

刪除測試

    args = make(map[string] interface{})    args["id"] = 1    rs = db.Delete(nil, args)    fmt.Println(rs)

批量測試

    vs := make([]map[string]interface{}, 0)    params := make(map[string] interface{})    params["name"] = "golang批量11213"        //第一個對象    params["isbn"] = "4156s5"    params["status"] = 5    params["id"] = 9    vs = append(vs, params)    params = make(map[string] interface{})    params["name"] = "golang批量22af24"        //第二個對象    params["isbn"] = "xxfqwt325rqrf45"    params["status"] = 2    params["id"] = 10    vs = append(vs, params)    db := &table    rs := db.InsertBatch("books", vs)    fmt.Println(rs)

項目地址

https://github.com/zhoutk/goTools

使用方法

git clone https://github.com/zhoutk/goToolscd goToolsgo getgo run bock.gogo buid bock.go./bock        

小結

經過多種方案的對比,發現go語言作為網路服務的吞吐率是最棒的,所以有了將以往在其它平台上的經驗(node.js,java,python3),用go來實現,期望有驚喜,寫代碼我是認真的。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.