欢迎访问我的博客,你的支持,是我最大的动力!

Go语言学习笔记(6)-RPC/数据库/Cookie

Linux 小马奔腾 518℃ 评论
目录:
[显示]

网络编程

RPC 编程

远程过程调用,使函数调用模式网络化

内部操作步骤:
1、调用客户句柄,执行传送参数
2、调用本地系统内核发送网络消息
3、消息传送到远程主机
4、服务器句柄得到消息并取得参数
5、执行远程过程
6、执行的过程将结果返回服务器句柄
7、服务器句柄返回结果,调用远程系统内核
8、消息传回本地主机
9、客户句柄从内核接收消息
10、客户接收句柄返回的数据

Go提供三个级别的RPC:TCP HTTP JSONRPC
Go的RPC只支持Go语言开发的服务端和客户端交互,因为内部采用了Gob编码

函数被远程访问的条件:
函数是导出的
必须有两个导出类型的参数
第一个参数是接收参数,第二个是返回给客户端的参数,第二个参数必须是指针类型
函数要有一个返回值 error
如:
func (t *T) MethodName(argType T1, replyType *T2) error
T T1 T2类型必须能被encoding/gob编解码

HTTP RPC

服务端

客户端

客户端最重要的是client.Call函数
第一个参数是要调用的函数的名字;第二个是要传递的参数;第三个是要返回的参数(指针类型)

TCP RPC

服务端

客户端

JSON RPC

数据编码采用JSON,而不是Gob编码,需要使用 net/rpc/jsonrpc 包
json-rpc是基于TCP协议的,还不支持HTTP方式

服务端

客户端

RPC 接口

可以自定义数据的传输方式以及RPC服务器与客户端之前的交互行为

RPC编码解码器接口
type ClientCodec interface {
WriteRequest(*Request, interface{}) error
ReadResponseHeader(*Response) error
ReadResponseBody(interface{}) error
Close() error
}
type ServerCodec interface {
ReadRequestHeader(*Request) error
ReadRequestBody(interface{}) error
WriteResponse(*Response, interface{}) error
Close() error
}
数据库

Go没有内置的驱动支持任何数据库,但定义了database/sql接口,可基于驱动接口开发相应数据库的驱动
范例及说明 http://go-database-sql.org/

database/sql 接口

使用 database/sql 的数据库驱动,可以任意更换数据库,但代码不需要做改动

sqlite3:https://github.com/mattn/go-sqlite3  安装:go get github.com/mattn/go-sqlite3  (安装时需要有gcc 环境变量CGO_ENABLED=1)
mysql:https://github.com/go-sql-driver/mysql  安装:go get -u github.com/go-sql-driver/mysql

1、sql.Register
注册数据库驱动,通常在第三方开发的驱动的init函数中调用,进行注册
Register(name string, driver driver.Driver)

# sqlite3的注册函数
func init() {
sql.Register("sqlite3", &SQLiteDriver{})
}

database/sql内部通过map存储用户注册的驱动,只要名称不重复,可注册多个数据库驱动
var drivers = make(map[string]driver.Driver)
drivers[name]=driver
使用:

import (
"database/sql"
_ "github.com/mattn/go-sqlite3"  //仅执行init函数注册驱动
)

2、driver.Driver
Driver是数据库驱动的接口,它定义方法Open(name string) 返回数据库的Conn接口

type Driver interface {
Open(name string)(Conn,error)
}

注意,返回的Conn只能用来进行一次goroutine操作,不能应用于多个goroutine里
因为如果多个goroutine共用的话,无法确定某个操作是哪个goroutine发起的,而不知道将数据库的数据返回给谁

3、driver.Conn
数据库连接的接口定义,这个Conn只能应用在一个goroutine里面,不能用在多个goroutine

type Conn interface {
Prepare(query string)(Stmt, error)
Close() error
Begin()(Tx, error)
}

Prepare返回与当前连接相关的执行sql语句的准备状态,可进行查询、删除等操作
Close关闭当前的连接,释放连接拥有的资源。驱动实现了database/sql里的conn pool,所以不用再实现缓存conn之类,容易引起问题
Begin函数返回一个代表事务处理的Tx,通过它可进行查询、更新等操作,或对事务进行回滚、提交

4、driver.Stmt
一种准备好的状态,和Conn相关联,只能应用于一个goroutine

type Stmt interface {
Close() error
NumInput() int
Exec(args []Value)(Result, error)
Query(args []Value)(Rows, error)
}

Close关闭当前的连接状态,若正在执行query,query还是会有效返回rows数据
NumInput返回当前预留参数个数
Exec函数执行Prepare准备好的sql,传入参数执行update/insert等作响,返回Result数据
Query函数执行Prepare准备好的sql,传入参数执行select操作,返回Rows数据

5、driver.Tx
事务处理,提交或回滚

type Tx interface {
Commit() error
Rollback() error
}

6、driver.Execer
这是Conn可选实现的接口,若没定义,调用DB.Exec,首先调用Prepare返回Stmt,然后执行Stmt的Exec,最后关闭Stmt

type Execer interface {
Exec(query string, args []Value)(Result, error)
}

7、driver.Result
执行update/insert等操作返回的结果

type Result interface {
LastInsertId()(int64, error)
RowsAffected()(int64, error)
}

LastInsertId返回数据库执行插入得到的自增ID号
RowsAffected函数返回query操作影响的数据条目数

8、driver.Rows
执行查询返回的结果集

type Rows interface {
Columns()[]string
Close() error
Next(dest []Value) error
}

Columns返回查询数据库表的字段信息,这个slice与sql中的字段一一对应,不是返回整个表的所有字段
Close用来关闭Rows迭代器
Next用来返回下一条数据,把数据赋值给dest dest里面的元素必须是driver.Value的值(除了string),返回的数据里面所有string必须转换成[]byte,若最后数据没有了,返回io.EOF

9、driver.RowsAffected
RowsAffected实际是int64的一个别名,实现了Result接口

type RowsAffected int64
func (RowsAffected) LastInsertId()(int64, error)
func (v RownsAffected) RowsAffected()(int64, error)

10、driver.Value
是一个空接口

type Value interface{}

Value必须是驱动能操作的类型,要么是nil,要么是int64、float64、bool、[]byte、string(除了Rows.Next,返回的不能是string)、time.Time

11、driver.ValueConverter
定义如何把普通值转化成driver.Value的接口

type ValueConverter interface {
ConvertValue(v interface{})(Value, error)
}

转化driver.Value到数据库表相应字段,如int64->uint16
把数据库查询结果转化成driver.Value值
在scan函数里把driver.Value转化成用户定义的值

12、driver.Valuer
定义返回一个driver.Value的方式

type Valuer interface {
Value()(Value, error)
}

用于自身与driver.Value的转化

MySQL数据库

几种驱动实现
https://github.com/go-sql-driver/mysql 支持database/sql 全部用go编写,支持keepalive  【推荐】
安装:go get -u github.com/go-sql-driver/mysql
https://github.com/mikespook/mymysql 支持database/sql 也支持自定义接口,全部用go编写
安装:go get github.com/mikespook/mymysql
https://github.com/Philio/GoMySQL 不支持database/sql 自定义接口,全部采用go编写
安装:go get github.com/Philio/GoMySQL

示例:
数据库 192.168.1.78 test test123 test库

sql.Open()打开一个注册过的数据库,db.Close()关闭数据库连接
db.Prepare()准备要执行的sql操作,返回准备完毕的执行状态
db.Query()直接执行sql返回rows结果
stmt.Exec()执行sql语句

SQLite数据库

SQLite是开源的嵌入式关系型数据库,实现自包容、零配置、支持事务的SQL数据库引擎,特点是高度便携、使用方便、结构紧凑、高效、可靠

几种驱动实现:
https://github.com/mattn/go-sqlite3 支持database/sql,基于cgo 【推荐】
需要gcc 在windows下,下载并安装 tdm64-gcc-5.1.0-2.exe
安装:go get -u github.com/mattn/go-sqlite3
https://github.com/feyeleanor/gosqlite3 不支持database/sql,基于cgo
安装:go get github.com/feyeleanor/gosqlite3
https://github.com/phf/go-sqlite3 不支持database/sql,基于cgo
安装:go get github.com/phf/go-sqlite3

示例:建表语句和mysql的有区别

PostgreSQL 数据库

PostgreSQL相对于MySQL更加庞大,因为它是用来替代Oracle的

几种驱动实现:
https://github.com/lib/pq  支持database/sql驱动,纯go编写 【推荐】
安装:go get github.com/lib/pq
https://github.com/jbarham/gopgsqldriver  支持database/sql驱动,纯go编写
安装:go get github.com/jbarham/gopgsqldriver
https://github.com/lxn/go-pgsql  支持database/sql驱动,纯go编写
安装:go get github.com/lxn/go-pgsql

区别:

db,err := sql.Open("postgres","user=zuolan password=zuolan dbname=test sslmode=disable")
INSERT INTO userinfo(username,departname,created) VALUES($1,$2,$3) RETURNING uid
pg不支持res.LastInsertId() 因为它没有自增ID
pg是通过$1 $2这种方式指定要传递的参数的
NoSQL数据库

Redis、MongoDB、Cassandra、Membase等

Redis
驱动:
https://github.com/garyburd/redigo
https://github.com/go-redis/redis 【推荐】
https://github.com/hoisie/redis
https://github.com/alphazero/Go-Redis
https://github.com/simonz05/godis

MongoDB
驱动:
http://labix.org/mgo
安装:go get gopkg.in/mgo.v2

Go使用Cookie

Cookie是客户端机制,把用户数据保存在客户端
Session是服务端机制,服务端保存数据,使用唯一标识符sessionID,要么经过url传递,要么保存在客户端Cookie里

设置Cookie
使用net/http包的SetCookie来设置

http.SetCookie(w ResponseWriter, cookie *Cookie)

w表示要写入的response cookie是一个结构体

expiration := time.Now()
expiration = expiration.AddDate(1,0,0)
cookie := http.Cookie{Name:"username",Value:"zuolan",Expires: expiration}
http.SetCookie(w,&Cookie)

读取Cookie

cookie,_ := r.Cookie("username")
fmt.Fprint(w,cookie)
或者
for _,cookie := range r.Cookies() {
fmt.Fprint(w,cookie.Name)
}

 

转载请注明:轻风博客 » Go语言学习笔记(6)-RPC/数据库/Cookie

喜欢 (0)or分享 (0)