GoLang学习(四)

现如今做个产品避免不了要用到数据库,GoLang做为新语言当然也提供了相关的函数库。运行环境中提供了database/sql模块,这个里面相当于Java的JDBC做了做了一些规范,但不同的是它默认有了一些实现。
GoLang对数据库的操作用起来很简单,不用写太多的代码,相对来说功能也比较少,日常用到的功能差不多都有了,没有找到批量提交功能。

以MySQL数据库举例,这也是最常用的数据库了,首先去官网下载驱动程序。

//要导入相关模块
import "database/sql"
import _ "github.com/go-sql-driver/mysql"
import "fmt"
 
func test1(){
//这个URL地址看起来很奇怪
//完成的格式:[username[:password]@][protocol[(address)]]/dbname[?param1=value1&...&paramN=valueN]
db, e := sql.Open("mysql", "user:[email protected](1.1.1.1:3306)/databasename?charset=utf8")
defer db.Close()
if e!=nil{
    fmt.Printf("open Db error : %s\n",e.Error())
}
//接受一个interface{}数组做为参数,interface还不支持自定义结构。
rows,e := db.Query("select a,b,c from  xxxxx where x=? limit 10",10)
//打印出结果集中全部的列。
if columns ,err := rows.Columns();err==nil{
    fmt.Printf("columns : %#v\n",columns)
}
if e==nil{
   for ;rows.Next();{
        var a int
        var b int
        var c int
        //看到Scan函数别高兴,它同样不支持自定义的结构。
        e:=rows.Scan(&a,&b,&c)     
        if e==nil{
            fmt.Printf("result : %#v\n",obj)
        }else{
            fmt.Printf("scan error : %s\n",e.Error())
        }
   }
   rows.Close()
}
}
func main(){
test1()
}

DB结构里面还有预处理方法、事务方法、DB本身就是一个连接池。用起来很方便,使用很少的代码完成工作。。。。
入门扫盲结束,下一次介绍如何实现类似iBatis这样的轻量级框架。。。

GoLang学习(三)

本章节主要是Json编码/解码,golang里面的json编码/解码比python还简单,运行环境内置了json函数库,不需要单独安装模块;另外,可以支持自定义struct编解码和Java中的类似,可以把json转换成有类似属性的某个类。有一点需要注意,结构体中如果包含结构体,最好别用指针,否则用起来比较麻烦。

1、非指针方式,以下代码运行和预期一样

//导入模块
import(
        "fmt"
        "encoding/json"
      )
//定义两个数据结构
type Item struct{
    SName string
    IValue int
}
type JObject struct{
    IValue int
    SValue string
    SArray []string
    IArray[] int
    SIMap map[string]int
    OArray []Item
    SOMap map[string]Item
}
//编解码函数
func testEncoding(){
    var obj JObject
        obj.IValue=1
        obj.SValue="this is string"
        obj.IArray=[]int{1,2,3,4,5,5}
        obj.SArray=make([]string,10)
        obj.SIMap=make(map[string]int)
        obj.SIMap["akey"]=1
        obj.SIMap["bkey"]=2
        var item1 Item
            item1.SName="item name"
            item1.IValue=1
        obj.OArray=make([]Item,10)
        obj.OArray[0]=item1
        obj.SOMap=make(map[string]Item)
        obj.SOMap["abc"]=item1
    buf,err :=json.Marshal(&obj)
    if err==nil{
        fmt.Printf("encoding : %s\n",string(buf))
    }else{
        fmt.Printf("encoding error : %s\n",err.Error())
    }
}
func testDecoding(){
    var jsonstring=`{"IValue":1,"SValue":"this is string","SArray":["","","","","","","","","",""],"IArray":[1,2,3,4,5,5],"SIMap":{"akey":1,"bkey":2},"OArray":[{"SName":"item name","IValue":1},null,null,null,null,null,null,null,null,null],"SOMap":{"abc":{"SName":"item name","IValue":1}}}`
    var obj JObject
    err :=json.Unmarshal([]byte(jsonstring),&obj)
    if err==nil{
        fmt.Printf("json decode result : %#v\n",obj)
    }else{
        fmt.Printf("encoding error : %s\n",err.Error())
    }
}
//main函数
func main(){
    testEncoding()
    testDecoding()
}

2、把结构体JObject里面的某个属性修改成指针类型;

type JObject struct{
    IValue int
    SValue string
    SArray []string
    IArray[] int
    SIMap map[string]int
    OArray []*Item   //此处修改成指针数组
    SOMap map[string]Item
}
//编码解码函数需要做相应的调整
func testEncoding(){
    var obj JObject
        obj.IValue=1
        obj.SValue="this is string"
        obj.IArray=[]int{1,2,3,4,5,5}
        obj.SArray=make([]string,10)
        obj.SIMap=make(map[string]int)
        obj.SIMap["akey"]=1
        obj.SIMap["bkey"]=2
        var item1 Item
            item1.SName="item name"
            item1.IValue=1
        obj.OArray=make([]*Item,10)  //此处修改为指针类型
        obj.OArray[0]=&item1  //此处
        obj.SOMap=make(map[string]Item)
        obj.SOMap["abc"]=item1
    buf,err :=json.Marshal(&obj)
    if err==nil{
        fmt.Printf("encoding : %s\n",string(buf))
    }else{
        fmt.Printf("encoding error : %s\n",err.Error())
    }
}
 
//解码函数
func testDecoding(){
    var jsonstring=`{"IValue":1,"SValue":"this is string","SArray":["","","","","","","","","",""],"IArray":[1,2,3,4,5,5],"SIMap":{"akey":1,"bkey":2},"OArray":[{"SName":"item name","IValue":1},null,null,null,null,null,null,null,null,null],"SOMap":{"abc":{"SName":"item name","IValue":1}}}`
    var obj JObject
        obj.OArray=make([]*Item,10) //A:此处初始化一个数组
        var item1 Item
        obj.OArray[0]=&item1 //B:此处引用
    err :=json.Unmarshal([]byte(jsonstring),&obj)
    if err==nil{
        fmt.Printf("item1 : %#v\n",item1)
        fmt.Printf("json decode result : %#v\n",obj)
    }else{
        fmt.Printf("encoding error : %s\n",err.Error())
    }
}

编码运行结果:通第一个例子
解码运行结果:

item1 : main.Item{SName:"item name", IValue:1}
json decode result : main.JObject{IValue:1, SValue:"this is string", SArray:[]string{"", "", "", "", "", "", "", "", "", ""}, IArray:[]int{1, 2, 3, 4, 5, 5}, SIMap:map[string]int{"akey":1, "bkey":2}, OArray:[]*main.Item{(*main.Item)(0x21021d200), (*main.Item)(nil), (*main.Item)(nil), (*main.Item)(nil), (*main.Item)(nil), (*main.Item)(nil), (*main.Item)(nil), (*main.Item)(nil), (*main.Item)(nil), (*main.Item)(nil)}, SOMap:map[string]main.Item{"abc":main.Item{SName:"item name", IValue:1}}}

数组第一个元素是非空的,因为预先给这个指针引用了一个数据,如果在解码函数中去掉A到B三行,解码出来的数组都会是(nil)。
这就引发一个问题,一般我们不知道数组的长度是多少,也就是A处无法写长度,那么就无法正确解码出来了,得到的都是(nil)。
看decode.go代码的实现,没有对指针的处理,也就是遇到指针的情况没有处理。仔细想是对的,解码函数内部不应该[分配内存]返回一个指针,这个恰恰是调用者应该做的。

所以,如果不用指针用起来会更方便。

————–EOF————–