169

I am looking for a reliable solution to connect to a MySQL database from Go. I've seen some libraries around, but it is difficult to determine the different states of completeness and current maintenance. I don't have complex needs, but I'd like to know what people are relying on or the most standard solution to connect to MySQL.

Amin Shojaei
  • 5,451
  • 2
  • 38
  • 46
Sergi Mansilla
  • 12,495
  • 10
  • 39
  • 48

3 Answers3

267

A few drivers are available but you should only consider those that implement the database/sql API as

  • it provides a clean and efficient syntax,
  • it ensures you can later change the driver without changing your code, apart the import and connection.

Two fast and reliable drivers are available for MySQL :

I've used both of them in production, programs are running for months with connection numbers in the millions without failure.

Other SQL database drivers are listed on go-wiki.

Import when using MyMySQL :

import (
    "database/sql"
    _ "github.com/ziutek/mymysql/godrv"
)

Import when using Go-MySQL-Driver :

import (
    "database/sql"
    _ "github.com/go-sql-driver/mysql"
)

Connecting and closing using MyMySQL :

con, err := sql.Open("mymysql", database+"/"+user+"/"+password)
defer con.Close()
// here you can use the connection, it will be closed when function returns

Connecting and closing using Go-MySQL-Driver :

con, err := sql.Open("mysql", store.user+":"+store.password+"@/"+store.database)
defer con.Close()

Select one row :

row := con.QueryRow("select mdpr, x, y, z from sometable where id=?", id)
cb := new(SomeThing)
err := row.Scan(&cb.Mdpr, &cb.X, &cb.Y, &cb.Z)

Select multiple rows and build an array with results :

rows, err := con.Query("select a, b from item where p1=? and p2=?", p1, p2)
if err != nil { /* error handling */}
items := make([]*SomeStruct, 0, 10)
var ida, idb uint
for rows.Next() {
    err = rows.Scan(&ida, &idb)
    if err != nil { /* error handling */}
    items = append(items, &SomeStruct{ida, idb})
}

Insert :

_, err = con.Exec("insert into tbl (id, mdpr, isok) values (?, ?, 1)", id, mdpr)

You'll see that working in Go with MySQL is a delightful experience : I never had a problem, my servers run for months without errors or leaks. The fact that most functions simply take a variable number of arguments lighten a task which is tedious in many languages.

Note that if, in the future, you need to use another MySQL driver, you'll just have to change two lines in one go file : the line doing the import and the line opening the connection.

Denys Séguret
  • 372,613
  • 87
  • 782
  • 758
  • 2
    Thank you so much, I'll give it a try. I love that Go provides the database/sql package that libraries can implement. – Sergi Mansilla Jul 08 '12 at 00:09
  • It's similar to what exists in other languages (for example JDBC), but with a cleaner and lighter syntax. – Denys Séguret Jul 08 '12 at 07:15
  • 9
    Excellent primer for newbies. Thanks. – Rick-777 Nov 26 '12 at 20:53
  • 5
    A list of tested drivers (for other DBMSs, too) is available at http://code.google.com/p/go-wiki/wiki/SQLDrivers There is a second popular MySQL-driver: https://github.com/Go-SQL-Driver/MySQL/ (written by me) – Julien Schmidt Jan 13 '13 at 03:31
  • 1
    @JulienSchmidt I edited my answer to reference your link. If you happen to have a link to a comparison between those two drivers, it would be welcome. – Denys Séguret Jan 13 '13 at 10:02
  • @dystroy I don't have a link, but I try to sum it up: mymysql was written even before the database/sql interface was available. So mymysql was initially a stand-alone MySQL-Connector for Go. Later an adapter for database/sql (the godrv package) was added (But it can still work as a stand-alone connector). [Go-MySQL-Driver](https://github.com/Go-SQL-Driver/MySQL/) was written as a direct implementation of the database/sql interface, which removes a lot of overhead. – Julien Schmidt Jan 13 '13 at 19:23
  • Without any comparison or benchmark, it's hard to take this as a fact. As you're the author (and a promoter ardent enough to be the first to downvote my answer), you should think about putting in place such a benchmark if you think there is a noticeable difference. A few comments in SO aren't enough to present a new driver, especially if you think it should replace in use the older one. – Denys Séguret Jan 13 '13 at 19:32
  • Obvious is, that it removes a lot of overhead in terms of unnecessary function calls and also some type conversions. But you are right, real differences in terms of performance could be proven by a benchmark. You could take [go-sql-test](https://github.com/bradfitz/go-sql-test) (Thats what the drivers at code.google.com/p/go-wiki/wiki/SQLDrivers are tested with) or [my fork for current sources](https://github.com/Go-SQL-Driver/SQL-Test) as a simple benchmark by running it with `go test -v`. For most of the tests the runtime is to short to be suitable but others indicate a better performance. – Julien Schmidt Jan 13 '13 at 20:09
  • @Arne Thanks. Was this benchmark discussed somewhere (SO comments not being the best place to discuss) ? – Denys Séguret Mar 21 '13 at 08:27
  • Not discussed, but it was [announced on the go-nuts mailing list](https://groups.google.com/forum/?fromgroups=#!topic/golang-nuts/vYnSS_ABr4M). It's written by the developer of go-sql-drive/mysql (renamed to all lowercase), but the developer of mymysql also took part in the discussion. The benchmark is a little hard to run, but I contributed my own results from two machines (Linux 64 and OS X) and a script to make it easier on unixy machines. – Arne Mar 25 '13 at 09:03
  • @Arne Thanks. I'll keep a look on it and probably update my answer in next days or weeks. I notice that on 05 March the library author recommend *to wait some time ("a few weeks" should be enough) to feel certain that no bug slipped in*. The constructive competition between those 2 driver authors is good :) – Denys Séguret Mar 25 '13 at 09:12
  • Thanks for the update! Go-MySQL-Driver has just hit stable version 1.0 – Julien Schmidt May 14 '13 at 23:18
  • @JulienSchmidt Hi, I wanted to download your driver but I wasn't sure from the website if it is compatible with Windows. Is it? And why do I need to have Git installed on my computer? Thanks. – Zeynel Jul 06 '13 at 23:47
  • This way you can update it via the go get tool. But you can also just download a .zip from GitHub and unzip it in $GOPATH\src\github.com\go-sql-driver\ – Julien Schmidt Jul 07 '13 at 23:42
  • hi @dystroy: What does `cb := new(CompteBraldop)` do? What is `CompteBraldop`? It doesn't look like it is used again. I am trying to work with `go-sql-driver` Thanks. – Zeynel Jul 11 '13 at 12:07
  • 1
    @Zeynel It's just an example (taken from [this personal project](https://github.com/Canop/braldop)). I edited replacing it with `SomeThing`. The point of that line is to show how to directly fill a struct with the result of your query without intermediate variables. – Denys Séguret Jul 11 '13 at 12:11
  • Awesome thanks. When the connection is built can I access it from anywhere in my application? Yes, it is a n00b question :) – Ian Lewis Feb 11 '14 at 19:20
  • When running the code above in go 1.6 "Select multiple rows and build an array with results" Im getting undefined: Partage. Would be great to expand the example to show if Partage is a struct or exactly what it should be. Apologies for stupid question but Im not a seasoned go developer – Jeremy Quinton Apr 01 '16 at 10:34
  • @JeremyQuinton `Partage` is a struct, indeed. Is it clearer after the edit ? – Denys Séguret Apr 01 '16 at 10:36
  • @DenysSéguret yes that is a bit more clear thanks very much. Coming from dynamically typed languages(Ruby, PHP) the simple is not always obvious. Appreciate the edit. – Jeremy Quinton Apr 01 '16 at 10:50
  • With the mymysql-example, what is `database`? The IP:Port or the default database to use? In any case, where do I place the opposite? In my case I cant figure out how to pass the connection itself (IP and port). – C4d Aug 09 '18 at 12:58
  • To connect MyMySQL to a specific IP address `ADDR` with options `OPTIONS` use the full form `tcp:ADDR,OPTIONS*DBNAME/USER/PASSWD` – karmakaze Dec 12 '19 at 01:17
  • To connect Go-MySQL-Driver to a specific address:port with options use the full form `:@tcp(:)/?option1=value1&option2=value2` – karmakaze Dec 12 '19 at 01:21
2

few things to take note the select 1 row example :

row := con.QueryRow("select mdpr, x, y, z from sometable where id=?",id) 
cb := new(SomeThing) 
err := row.Scan(&cb.Mdpr, &cb.X, &cb.Y, &cb.Z)

there is a missing row.Next() in this example. it need to call the row.Next() to grab the first row returned.

also there is some inflexibility to the library which in some way try to promote data minimalism. if you try to select columns that is not Scan it will throw errors (not just warnings)

Badoet
  • 21
  • 2
  • 2
    This isn't accurate: the QueryRow function returns *Row. This function asserts that the query returns a single row. Query() returns (*Rows, error), which does require a call to rows.Next(). – Alan LaMielle Jun 30 '14 at 23:40
0

I see the Gorm as a perfect way to connect to Mysql or PostgreSQL.

Amin Shojaei
  • 5,451
  • 2
  • 38
  • 46