mymysql, 在Go中,MySQL客户端API完全编写

作者:无名 - GitHub -

  • 源代码名称:mymysql
  • 源代码网址:http://www.github.com/ziutek/mymysql
  • mymysql源代码文档
  • mymysql源代码下载
  • git url:
    git://www.github.com/ziutek/mymysql.git
  • git clone代码到本地:
    git clone http://www.github.com/ziutek/mymysql
  • subversion代码到本地:
    $ svn co --depth empty http://www.github.com/ziutek/mymysql

    checked out revision 1.

    $ cd repo

    $ svn up trunk

  • 对不起,我的英语不好。 如果你能帮助改善本文档中的英文,请与我联系。

    mymysql v1.5.4 ( 2015-01-08 )

    这个软件包包含了完全用go编写的mysql客户端 api。 它被设计为使用 greater 协议版本 4.1或者。 它绝对适用于mysql服务器版本 5.0和 5.1 ( 我在应用程序中使用了这些版本的mysql服务器)。 一些人声称mymysql与老版本的mysql协议一起工作。

    变更日志

    v1.5.4: bug 固定在本机和godrv软件包中。

    v1.5.3: bug 固定在新的godrv代码中。

    v1.5.1: 添加了 conn.netconn 方法。

    v1.5: 需要进行 1.1 (。time。parseinlocation和 net ) 编译。

    v1.4: stmt.resetparamsstmt.mapstmt.numfields 方法消失。 新的stmt.fields 方法。godrv 实现 driver.queryer 接口,它在编译时提高了性能。

    v1.3: 综合性能由因子 1.5提高至 1.8. 所有encode*函数现在都接受大小合适的[]byte 切片作为第一个参数。

    v1.2: 在 mymysql/godrv 中快速执行简单查询。 escapestring 方法重命名为 escape

    1: 客户端错误代码从 mymysql/native pacage到 mymysql/mysql。

    v1.0: 添加到autorc的事务,新的transaction.isvalid 方法。 我认为这个库已经足够成熟,可以将它的发布为 v1.0

    v0.4.11: 添加重新连接,register,setmaxpktsize,绑定到 autorc。

    v0.4.10: 新建克隆用于从其他连接创建连接的方法。

    v0.4.9: file: newfromcf 中从配置创建连接的新方法。

    v0.4.8: 从结果集中只获取第一个/最后一行的新方法。 结束方法中丢弃行的更好实现。

    v0.4.7: scanrow和makerow方法 addad。 由于scanrow不为从服务器接收的每一行分配内存,所以比getrow更高效。 godrv value.next 方法现在使用新的scanrow方法。

    v0.4.6: 添加到 mysql.result的statusonly方法。

    v0.4.5: 新的autorc.conn.prepareonce 方法。

    v0.4.4:

    • 行。int,row.uint, row.int64,。方法在出现错误时将立即出现紧急情况。
    • 新 row.float 方法。

    v0.4.3:

    • 修正了服务器返回mysql_type_newdecimal时出现的问题。
    • 小数作为 float64 ( 以前,它们作为 [] 字节返回) 返回。

    v0.4.2:

    • mysql时间处理的许多更改:
    • 日期时间类型被 time.time. 替换
    • 由 time.duration 替换的时间类型。
    • 支持添加到godrv中的time.time 类型。

    /rows。uint64方法已经添加。

    将bindparams重命名为绑定。

    v0.4.1:

    bindparams支持 go bool。

    v0.4:

    • 模块化设计:
    • 移动到 mymysql/本机的mysql协议处理。
    • 本机的线程安全包装器,位于独立的/thrsafe
    • mymysql/mysql 软件包包含了引擎和通用( 引擎独立) 函数接口的定义。
    • 自动重新连接接口移动到 mymysql/autorc。

    mysql.new 和其他函数主要返回接口类型。 所以所有以前导出的成员都被转换为方法( 除了 mysql.row 和 mysql.field 它们的定义没有变化)。

    已经添加事务如果使用 *mymysql/thrsafe" 引擎事务,则完全线程安全。

    用于 /sql的驱动程序。

    安装

    要安装所有 mymysql,你需要获得三个:

    $ go get github.com/ziutek/mymysql/thrsafe

    $ go get github.com/ziutek/mymysql/autorc

    $ go get github.com/ziutek/mymysql/godrv

    或者只运行一个命令来获取所有子软件包:

    $ go get -v github.com/ziutek/mymysql/...

    你去,自动选择合适的版本 mymysql for。 在这个命令之后,mymysql 就可以使用了。

    测试

    为了进行测试,你需要创建测试数据库和测试用户:

    mysqlgt; create database test;

    mysqlgt; grant all privileges on test.* to testuser@localhost;

    mysqlgt; set password for testuser@localhost = password("testpasswd9");

    确保中的mysql max_allowed_packet 变量等于或者等于 34m。

    默认的mysql服务器地址是 127.0.0.1: 3306.

    下一次运行测试:

    $ cd $gopath/src/github.com/ziutek/mymysql

    $./all.bash test

    示例

    示例 1

    package main

    import (

    "os"

    "github.com/ziutek/mymysql/mysql"

    _"github.com/ziutek/mymysql/native"//native engine

    //_"github.com/ziutek/mymysql/thrsafe"//thread safe engine

    )

    func main() {

    db := mysql.new("tcp","","127.0.0.1:3306", user, pass, dbname)

    err := db.connect()

    if err!= nil {

    panic(err)

    }

    rows, res, err := db.query("select * from x where idgt; %d", 20)

    if err!= nil {

    panic(err)

    }

    for _, row := range rows {

    for _, col := range row {

    if col == nil {

    //col has null value

    } else {

    //do something with text in col (type []byte)

    }

    }

    //you can get specific value from a row

    val1 := row[1].([]byte)

    //you can use it directly if conversion isn't needed

    os.stdout.write(val1)

    //you can get converted value

    number := row.int(0)//zero value

    str := row.str(1)//first value

    bignum := row.mustuint(2)//second value

    //you may get values by column name

    first := res.map("firstcolumn")

    second := res.map("secondcolumn")

    val1, val2 := row.int(first), row.str(second)

    }

    }

    如果你不想将整个结果加载到内存中,你可以使用 start start和getrow方法:

    res, err := db.start("select * from x")

    checkerror(err)

    //print fields names

    for _, field := range res.fields() {

    fmt.print(field.name,"")

    }

    fmt.println()

    //print all rows

    for {

    row, err := res.getrow()

    checkerror(err)

    if row == nil {

    //no more rows

    break

    }

    //print all cols

    for _, col := range row {

    if col == nil {

    fmt.print("lt;nullgt;")

    } else {

    os.stdout.write(col.([]byte))

    }

    fmt.print("")

    }

    fmt.println()

    }

    getrow方法为每个接收的行分配一个新的内存块。 如果查询返回数百个行,则应选择scanrow方法以避免不必要的分配:

    //print all rows

    row := res.makerow()

    for {

    err := res.scanrow(row)

    if err == io.eof {

    //no more rows

    break

    }

    checkerror(err)

    //print all cols

    //[...]

    }

    示例 2---预编译语句

    可以使用 run run run或者 exec 方法对prepared语句执行下列操作:

    stmt, err := db.prepare("insert into x values (,)")

    checkerror(err)

    type data struct {

    id int

    tax *float32//nil means null

    }

    data = new(data)

    for {

    err := getdata(data)

    if err == endofdata {

    break

    }

    checkerror(err)

    _, err = stmt.run(data.id, data.tax)

    checkerror(err)

    }

    getdata是从某个地方检索数据并设置数据结构的id id和tax的函数。 如果 tax字段字段getdata可以为检索到的变量指定指针,如果应该将null存储在数据库中。

    如果将参数传递给运行或者exec方法,则在每个方法调用中都会反弹。 如果语句将执行多次,则这是无效的。 在不使用参数的情况下,可以绑定参数和使用 run run或者执行方法,以避免这些不必要的。 如果你在多线程应用程序中使用绑定,那么在你不再需要绑定参数之前,应该确保没有其他线程使用绑定。

    绑定参数的最简单方法是:

    stmt.bind(data.id, data.tax)

    但是在我们的示例中不能使用它,因为 bound bound的参数不能由 函数更改。 你可以像这样修改绑定:

    stmt.bind(amp;data.id, amp;data.tax)

    现在它应该能正常工作了。 但是在我们的例子中有更好的解决方案:

     

    stmt.bind(data)

    但是方法有一个参数,并且这个参数是结构或者指向结构的指针,它将这个结构的所有字段当作参数,并将它们绑定到一个,。

    这是前一个示例的改进代码:

    data = new(data)

    stmt.bind(data)

    for {

    err := getdata(data)

    if isendofdata(error) {

    break

    }

    checkerror(err)

    _, err = stmt.run()

    checkerror(err)

    }

    示例 3-- 使用sendlongdata与 http.get 结合使用

    _, err = db.start("create table web (url varchar(80), content longblob)")

    checkerror(err)

    ins, err := db.prepare("insert into web values (,)")

    checkerror(err)

    var url string

    ins.bind(amp;url, []byte(nil))//[]byte(nil) for properly type binding

    for {

    //read url from stdin

    url =""

    fmt.scanln(amp;url)

    if len(url) == 0 {

    //stop reading if url is blank line

    break

    }

    //make a connection

    resp, err := http.get(url)

    checkerror(err)

    //we can retrieve response directly into database because

    //the resp.body implements io.reader. use 8 kb buffer.

    err = ins.sendlongdata(1, resp.body, 8192)

    checkerror(err)

    //execute insert statement

    _, err = ins.run()

    checkerror(err)

    }

    示例 4-- 多语句/多结果

    res, err := db.start("select id from m; select name from m")

    checkerror(err)

    //get result from first select

    for {

    row, err := res.getrow()

    checkerror(err)

    if row == nil {

    //end of first result

    break

    }

    //do something with with the data

    functionthatuseid(row.int(0))

    }

    //get result from second select

    res, err = res.nextresult()

    checkerror(err)

    if res == nil {

    panic("hmm, there is no result. why!")

    }

    for {

    row, err := res.getrow()

    checkerror(err)

    if row == nil {

    //end of second result

    break

    }

    //do something with with the data

    functionthatusename(row.str(0))

    }

    示例 5---事务

    import (

    "github.com/ziutek/mymysql/mysql"

    _"github.com/ziutek/mymysql/thrsafe"//for thread safe transactions

    )

    //[...]

    //statement prepared before transaction begins

    ins, err := db.prepare("insert a values (,)")

    checkerror(err)

    //begin a new transaction

    tr, err := db.begin()

    checkerror(err)

    //now db is locked, so any method that uses db and sends commands to

    //mysql server will be blocked until commit or rollback is called.

    //commands in transaction are thread safe to

    go func() {

    _, err = tr.start("insert a values (1, 'jeden')")

    checkerror(err)

    } ()

    _, err = tr.start("insert a values (2, 'dwa')")

    checkerror(err)

    //you can't use statements prepared before transaction in the usual way,

    //because the connection is locked by the begin method. you must bind the statement

    //to the transaction before using it.

    _, err = tr.do(ins).run(3,"three")

    checkerror(err)

    //for a greater number of calls

    ti := tr.do(ins)

    _, err = ti.run(4,"four")

    checkerror(err)

    _, err = ti.run(5,"five")

    checkerror(err)

    //at the end you can commit or rollback. tr is invalidated and using it

    //after commit/rollback will cause a panic.

    tr.commit()

    示例 6---autoreconn接口

    import (

    "github.com/ziutek/mymysql/autorc"

    _"github.com/ziutek/mymysql/thrsafe"//you may also use the native engine

    )

    //[...]

    db := autorc.new("tcp","","127.0.0.1:3306", user, pass, dbname)

    //initilisation commands. they will be executed after each connect.

    db.register("set names utf8")

    //there is no need to explicity connect to the mysql server

    rows, res, err := db.query("select * from r")

    checkerror(err)

    //now we are connected.

    //it does not matter if connection will be interrupted during sleep, eg

    //due to server reboot or network down.

    time.sleep(9e9)

    //if we can reconnect in no more than db.maxretries attempts this

    //statement will be prepared.

    sel, err := db.prepare("select name from r where idgt;")

    checkerror(err)

    //we can destroy our connection server side

    _, _, err = db.query("kill %d", db.raw.threadid())

    checkerror(err)

    //but it doesn't matter

    sel.bind(2)

    rows, res, err = sel.exec()

    checkerror(err)

    示例 7-- 使用mymysql驱动程序使用数据库/sql

    import (

    "database/sql"

    _"github.com/ziutek/mymysql/godrv"

    )

    //[...]

    //open new connection. the uri need to have the following syntax:

    //

    //[protocol_specfiic*]dbname/user/passwd

    //

    //where protocol specific part may be empty (this means connection to

    //local server using default protocol). currently possible forms:

    //dbname/user/passwd

    //unix:sockpath*dbname/user/passwd

    //unix:sockpath,options*dbname/user/passwd

    //tcp:addr*dbname/user/passwd

    //tcp:addr,options*dbname/user/passwd

    //

    //options can contain comma separated list of options in form:

    //opt1=val1,opt2=val2,boolopt3,boolopt4

    //currently implemented options:

    //laddr - local address/port (eg. 1.2.3.4:0)

    //timeout - connect timeout in format accepted by time.parseduration

    //register initialisation commands

    //(workaround, see http://codereview.appspot.com/5706047)

    godrv.register("set names latin2")//overrides default utf8

    godrv.register("create table if not exists my_table (.. . )")

    //create a connection handler

    db, err := sql.open("mymysql","test/testuser/testpasswd9")

    checkerr(err)

    //for other information about database/sql see its documentation.

    ins, err := db.prepare("insert my_table set txt=")

    checkerr(err)

    res, err := ins.exec("some text")

    checkerr(err)

    id, err := res.lastinsertid()

    checkerr(err)

    checkerr(ins.close(ins))

    rows, err := db.query("select * from go")

    checkerr(err)

    for rows.next() {

    var id int

    var txt string

    checkerr(rows.scan(amp;id, amp;txt))

    //do something with id and txt

    }

    checkerr(db.close())

    示例 8---使用存储过程

    import (

    "github.com/ziutek/mymysql/mysql"

    _"github.com/ziutek/mymysql/thrsafe"//or native

    )

    //[...]

    res, err := my.start("call myprocedure(1, 2, 3)")

    checkerr(err)

    //procedure can return more than one result set so we have to read all

    //results up to the result that doesn't include result set (status only

    //result).

    for!res.statusonly() {

    rows, err := res.getrows()

    checkerr(err)

    userows(rows)

    res, err := res.nextresult()

    checkerr(err)

    if res == nil {

    panic("nil result from procedure")

    }

    }

    示例 9-- 使用autorc的事务

    import (

    "github.com/ziutek/mymysql/autorc"

    _"github.com/ziutek/mymysql/thrsafe"//you may also use the native engine

    )

    //[...]

    db := autorc.new("tcp","","127.0.0.1:3306", user, pass, dbname)

    var stmt1, stmt2 autorc.stmt

    func updatedb() {

    err := db.prepareonce(amp;stmt1, somesql1)

    checkdberr(err)

    err = db.prepareonce(amp;stmt2, somesql2)

    checkdberr(err)

    err = db.begin(func(tr mysql.transaction, args.. .interface{}) error {

    //this function will be called again if returns a recoverable error

    s1 := tr.do(stmt1.raw)

    s2 := tr.do(stmt2.raw)

    if _, err := s1.run(); err!= nil {

    return err

    }

    if _, err := s2.run(); err!= nil {

    return err

    }

    //you have to commit or rollback before return

    return tr.commit()

    })

    checkdberr(err)

    }

    其他示例在示例目录中。

    类型映射

    对于经典文本查询,发送到mysql服务器的所有变量都嵌入到文本查询中。 因此,你总是将它们转换为字符串并将它们嵌入到sql查询中:

    rows, res, err := db.query("select * from x where idgt; %d", id)

    在文本查询之后,你总是收到一个文本结果。 mysql文本结果对应于mymysql中的[] 字节。 由于避免不必要的类型转换,它不是字符串类型。 你可以将字节的[] 字节转换为字符串

    fmt.print(string(rows[0][1].([]byte)))

    或者使用 str helper 方法:

    fmt.print(rows[0].str(1))

    还有其他用于数据转换的helper 方法,如 int int uint uint:::

    fmt.print(rows[0].int(1))

    上三个示例返回行 0列 1中收到的值。 如果你喜欢使用列名,可以使用 res.map 将结果字段名称映射到相应的索引:

    name := res.map("name")

    fmt.print(rows[0].str(name))

    在预编译语句中,类型映射稍微复杂一些。 对于从客户机发送到服务器的参数,go/mymysql类型映射为如下所示的mysql协议类型:

    string --gt; mysql_type_string

    []byte --gt; mysql_type_var_string

    int8, uint8 --gt; mysql_type_tiny

    int16, uint16 --gt; mysql_type_short

    int32, uint32 --gt; mysql_type_long

    int64, uint64 --gt; mysql_type_longlong

    int, uint --gt; protocol integer type which match size of int

    bool --gt; mysql_type_tiny

    float32 --gt; mysql_type_float

    float64 --gt; mysql_type_double

    time.time --gt; mysql_type_datetime

    mysql.timestamp --gt; mysql_type_timestamp

    mysql.date --gt; mysql_type_date

    time.duration --gt; mysql_type_time

    mysql.blob --gt; mysql_type_blob

    nil --gt; mysql_type_null

    mysql服务器映射/将它们转换为特定的mysql存储类型。

    对于收到的结果,mysql存储类型映射到如下所示的转/mymysql类型:

    tinyint --gt; int8

    unsigned tinyint --gt; uint8

    smallint --gt; int16

    unsigned smallint --gt; uint16

    mediumint, int --gt; int32

    unsigned mediumint, unsigned int --gt; uint32

    bigint --gt; int64

    unsigned bigint --gt; uint64

    float --gt; float32

    double --gt; float64

    decimal --gt; float64

    timestamp, datetime --gt; time.time

    date --gt; mysql.date

    time --gt; time.duration

    year --gt; int16

    char, varchar, binary, varbinary --gt; []byte

    text, tinytext, mediumtext, longtex --gt; []byte

    blob, tinyblob, mediumblob, longblob --gt; []byte

    bit --gt; []byte

    set, enum --gt; []byte

    null --gt; nil

    大数据包

    这个软件包可以发送和接收大于 16 mb的mysql数据包。 这意味着你可以接收到大于 16 mb的响应行,并且可以使用sendlongdata方法执行大于 16 mb的准备语句。 如果想使用这个特性,你需要使用 conn.setmaxpktsize 方法更改缺省的mymysql设置,并在你的mysql服务器配置中更改max_allowed_packet值。

    线程安全引擎

    如果导入"mymysql/thrsafe"引擎而不是"mymysql/本机"引擎,所有方法都是线程安全的,除非该方法的描述说明了其他。

    在calling查询/执行数据之前,如果一个线程正在调用查询或者执行数据的方法,其他线程将被阻塞,直到查询 start start exec return。

    在一个线程中,如果一个线程调用查询或者其他线程,那么其他线程会阻塞它,直到所有结果都从连接中开始。

    在我的大多数web应用程序中,我使用的是 autorecon 接口,它与的thrsafe引擎 engine。 对于任何新连接,都会创建一个 gorutine。 所有gorutines都有一个与mysql服务器共享的持久连接。 应用程序通常在带有gomaxprocs=2的双核心机器上运行。 在把它投入生产之前,我使用 siege来测试任何应用程序。 siege的输出示例如下:

    # siege my.httpserver.pl -c25 -d0 -t 30s

    ** siege 2.69

    ** preparing 25 concurrent users for battle.

    the server is now under siege...

    lifting the server siege.. done.

    transactions: 3212 hits

    availability: 100.00 %

    elapsed time: 29.83 secs

    data transferred: 3.88 mb

    response time: 0.22 secs

    transaction rate: 107.68 trans/sec

    throughput: 0.13 mb/sec

    concurrency: 23.43

    successful transactions: 3218

    failed transactions: 0

    longest transaction: 9.28

    shortest transaction: 0.01

    • 完整文档

    已知的bug

    • 在和函数中有 mysql"bug"。 如果使用预处理语句,sum 返回十进制值,即使你和整数列求和。 mymysql将十进制返回为 float64 因此转换结果从和到整数( 或者使用 row.int ) 导致恐慌。
    • 文档

    godrv



    文章标签:api

    IT人知识库 原文地址:http://www.itpeo.net/389612/4639498.html





    sensu-community-plugins, 用于检查,处理程序,&转换器的Sensu社区插件

    源代码名称:sensu-community-plugins源代码网址:http://www.github.com/sen ...

    sift.js, 使用mongodb查询筛选数组

    源代码名称:sift.js源代码网址:http://www.github.com/crcn/sift.jssift.js ...

    mp3fs, 基于保险丝的文件系统 从openssl转换为 MP3

    源代码名称:mp3fs源代码网址:http://www.github.com/khenriks/mp3fsmp3fs源代 ...

    ThinkComplexity2, 思考复杂性的书籍和代码,2nd 版

    源代码名称:thinkcomplexity2源代码网址:http://www.github.com/allendowne ...

    rfedfre

    Feeds-for-iOS-Developer, iOS开发人员的rss提要列表

    源代码名称:feeds-for-ios-developer源代码网址:http://www.github.com/rgn ...

    0CC-FamiTracker, jsr的FamiTracker扩展

    源代码名称:0cc-famitracker源代码网址:http://www.github.com/hertzdevil/ ...

    vrnetlab, 使用 Docker 运行虚拟路由器

    源代码名称:vrnetlab源代码网址:http://www.github.com/plajjan/vrnetlabvr ...

    deb.sury.org, 任何ppa的public bugreports

    源代码名称:deb.sury.org源代码网址:http://www.github.com/oerdnj/deb.sur ...

    moderncv, 一种面向 LaTeX的现代课程

    源代码名称:moderncv源代码网址:http://www.github.com/xdanaux/moderncvmo ...

    kickstart-meteor-react, 快速启动一个简单的项目 !

    源代码名称:kickstart-meteor-react源代码网址:http://www.github.com/ther ...

    geventhttpclient, 一个高性能并发的python 客户端库,带有 gevent

    源代码名称:geventhttpclient源代码网址:http://www.github.com/gwik/geven ...

    CeedGL, 基于 Mac &的现代OpenGL开发中的瘦 Objective C 封装

    源代码名称:ceedgl源代码网址:http://www.github.com/creaceed/ceedglceedg ...

    rfedfre

    pgadmin4-docker, pgAdmin4 Docker 映像的自动生成

    源代码名称:pgadmin4-docker源代码网址:http://www.github.com/thajeztah/p ...

    rfedfre

    DingDingLuckyMoney, DingDingLuckyMoney(钉钉红包插件)

    源代码名称:dingdingluckymoney源代码网址:http://www.github.com/veryyoun ...

    Jekyll-Mono, Jekyll是一个简单而优雅的GitHub概要和博客主题

    源代码名称:jekyll-mono源代码网址:http://www.github.com/akshayagarwal00 ...

    rfedfre

    webmagic-csdnblog, 基于WebMagic写的一个csdn博客小爬虫

    源代码名称:webmagic-csdnblog源代码网址:http://www.github.com/liyifeng1 ...

    rfedfre

    PassWordInput, A custom Password Input with animation for Android.

    源代码名称:passwordinput源代码网址:http://www.github.com/ldoublem/pass ...

    tensorflow-finetune-flickr-style, 在TensorFlow上,演示微调过程

    源代码名称:tensorflow-finetune-flickr-style源代码网址:http://www.githu ...

    android_anndblur, Android设备背景模糊效果的项目

    源代码名称:android_anndblur源代码网址:http://www.github.com/harism/and ...

    naemon-core, 网络,应用程序和事件监视器

    源代码名称:naemon-core源代码网址:http://www.github.com/naemon/naemon-c ...