Go
Examples on GitHub: sample_db, go
go-tarantool is the official Go connector for Tarantool. It is not supplied as part of the Tarantool repository and should be installed separately.
This tutorial shows how to use the go-tarantool 2.x library to create a Go application that connects to a remote Tarantool instance, performs CRUD operations, and executes a stored procedure. You can find the full package documentation here: Client in Go for Tarantool.
Note
This tutorial shows how to make CRUD requests to a single-instance Tarantool database. To make requests to a sharded Tarantool cluster with the CRUD module, use the crud package’s API.
This section describes the configuration of a sample database that allows remote connections:
credentials:
users:
sampleuser:
password: '123456'
privileges:
- permissions: [ read, write ]
spaces: [ bands ]
- permissions: [ execute ]
functions: [ get_bands_older_than ]
groups:
group001:
replicasets:
replicaset001:
instances:
instance001:
iproto:
listen:
- uri: '127.0.0.1:3301'
app:
file: 'myapp.lua'
- The configuration contains one instance that listens for incoming requests on the
127.0.0.1:3301
address. sampleuser
has privileges to select and modify data in thebands
space and execute theget_bands_older_than
stored function. This user can be used to connect to the instance remotely.myapp.lua
defines the data model and a stored function.
The myapp.lua
file looks as follows:
-- Create a space --
box.schema.space.create('bands')
-- Specify field names and types --
box.space.bands:format({
{ name = 'id', type = 'unsigned' },
{ name = 'band_name', type = 'string' },
{ name = 'year', type = 'unsigned' }
})
-- Create indexes --
box.space.bands:create_index('primary', { parts = { 'id' } })
box.space.bands:create_index('band', { parts = { 'band_name' } })
box.space.bands:create_index('year_band', { parts = { { 'year' }, { 'band_name' } } })
-- Create a stored function --
box.schema.func.create('get_bands_older_than', {
body = [[
function(year)
return box.space.bands.index.year_band:select({ year }, { iterator = 'LT', limit = 10 })
end
]]
})
You can find the full example on GitHub: sample_db.
Before creating and starting a client Go application, you need to run the sample_db application using tt start:
$ tt start sample_db
Now you can create a client Go application that makes requests to this database.
Before you start, make sure you have Go installed on your computer.
Create the
hello
directory for your application and go to this directory:$ mkdir hello $ cd hello
Initialize a new Go module:
$ go mod init example/hello
Inside the
hello
directory, create thehello.go
file for application code.
In the hello.go
file, declare a main
package and import the following packages:
package main
import (
"context"
"fmt"
"github.com/tarantool/go-tarantool/v2"
_ "github.com/tarantool/go-tarantool/v2/datetime"
_ "github.com/tarantool/go-tarantool/v2/decimal"
_ "github.com/tarantool/go-tarantool/v2/uuid"
"time"
)
The packages for external MsgPack types, such as datetime
, decimal
, or uuid
, are required to parse these types in a response.
Declare the
main()
function:func main() { }
Inside the
main()
function, add the following code:// Connect to the database ctx, cancel := context.WithTimeout(context.Background(), time.Second) defer cancel() dialer := tarantool.NetDialer{ Address: "127.0.0.1:3301", User: "sampleuser", Password: "123456", } opts := tarantool.Opts{ Timeout: time.Second, } conn, err := tarantool.Connect(ctx, dialer, opts) if err != nil { fmt.Println("Connection refused:", err) return } // Interact with the database // ...
This code establishes a connection to a running Tarantool instance on behalf of
sampleuser
. Theconn
object can be used to make CRUD requests and execute stored procedures.
Add the following code to insert four tuples into the bands
space:
// Insert data
tuples := [][]interface{}{
{1, "Roxette", 1986},
{2, "Scorpions", 1965},
{3, "Ace of Base", 1987},
{4, "The Beatles", 1960},
}
var futures []*tarantool.Future
for _, tuple := range tuples {
request := tarantool.NewInsertRequest("bands").Tuple(tuple)
futures = append(futures, conn.Do(request))
}
fmt.Println("Inserted tuples:")
for _, future := range futures {
result, err := future.Get()
if err != nil {
fmt.Println("Got an error:", err)
} else {
fmt.Println(result)
}
}
This code makes insert requests asynchronously:
- The
Future
structure is used as a handle for asynchronous requests. - The
NewInsertRequest()
method creates an insert request object that is executed by the connection.
Note
Making requests asynchronously is the recommended way to perform data operations. Further requests in this tutorial are made synchronously.
To get a tuple by the specified primary key value, use NewSelectRequest()
to create an insert request object:
// Select by primary key
data, err := conn.Do(
tarantool.NewSelectRequest("bands").
Limit(10).
Iterator(tarantool.IterEq).
Key([]interface{}{uint(1)}),
).Get()
if err != nil {
fmt.Println("Got an error:", err)
}
fmt.Println("Tuple selected by the primary key value:", data)
You can also get a tuple by the value of the specified index by using Index()
:
// Select by secondary key
data, err = conn.Do(
tarantool.NewSelectRequest("bands").
Index("band").
Limit(10).
Iterator(tarantool.IterEq).
Key([]interface{}{"The Beatles"}),
).Get()
if err != nil {
fmt.Println("Got an error:", err)
}
fmt.Println("Tuple selected by the secondary key value:", data)
NewUpdateRequest()
can be used to update a tuple identified by the primary key as follows:
// Update
data, err = conn.Do(
tarantool.NewUpdateRequest("bands").
Key(tarantool.IntKey{2}).
Operations(tarantool.NewOperations().Assign(1, "Pink Floyd")),
).Get()
if err != nil {
fmt.Println("Got an error:", err)
}
fmt.Println("Updated tuple:", data)
NewUpsertRequest()
can be used to update an existing tuple or insert a new one.
In the example below, a new tuple is inserted:
// Upsert
data, err = conn.Do(
tarantool.NewUpsertRequest("bands").
Tuple([]interface{}{uint(5), "The Rolling Stones", 1962}).
Operations(tarantool.NewOperations().Assign(1, "The Doors")),
).Get()
if err != nil {
fmt.Println("Got an error:", err)
}
In this example, NewReplaceRequest()
is used to delete the existing tuple and insert a new one:
// Replace
data, err = conn.Do(
tarantool.NewReplaceRequest("bands").
Tuple([]interface{}{1, "Queen", 1970}),
).Get()
if err != nil {
fmt.Println("Got an error:", err)
}
fmt.Println("Replaced tuple:", data)
NewDeleteRequest()
in the example below is used to delete a tuple whose primary key value is 5
:
// Delete
data, err = conn.Do(
tarantool.NewDeleteRequest("bands").
Key([]interface{}{uint(5)}),
).Get()
if err != nil {
fmt.Println("Got an error:", err)
}
fmt.Println("Deleted tuple:", data)
To execute a stored procedure, use NewCallRequest()
:
// Call
data, err = conn.Do(
tarantool.NewCallRequest("get_bands_older_than").Args([]interface{}{1966}),
).Get()
if err != nil {
fmt.Println("Got an error:", err)
}
fmt.Println("Stored procedure result:", data)
The CloseGraceful()
method can be used to close the connection when it is no longer needed:
// Close connection
conn.CloseGraceful()
fmt.Println("Connection is closed")
Note
You can find the example with all the requests above on GitHub: go.
Execute the following
go get
commands to update dependencies in thego.mod
file:$ go get github.com/tarantool/go-tarantool/v2 $ go get github.com/tarantool/go-tarantool/v2/decimal $ go get github.com/tarantool/go-tarantool/v2/uuid
To run the resulting application, execute the
go run
command in the application directory:$ go run . Inserted tuples: [[1 Roxette 1986]] [[2 Scorpions 1965]] [[3 Ace of Base 1987]] [[4 The Beatles 1960]] Tuple selected by the primary key value: [[1 Roxette 1986]] Tuple selected by the secondary key value: [[4 The Beatles 1960]] Updated tuple: [[2 Pink Floyd 1965]] Replaced tuple: [[1 Queen 1970]] Deleted tuple: [[5 The Rolling Stones 1962]] Stored procedure result: [[[2 Pink Floyd 1965] [4 The Beatles 1960]]] Connection is closed
Last update: January 2023
There are also the following community-driven Go connectors:
The table below contains a feature comparison for the connectors mentioned above.
tarantool/go-tarantool | viciious/go-tarantool | FZambia/tarantool | |
---|---|---|---|
License | BSD 2-Clause | MIT | BSD 2-Clause |
Last update | 2023 | 2022 | 2022 |
Documentation | README with examples and up-to-date GoDoc | README with examples, code comments | README with examples |
Testing / CI / CD | GitHub Actions | Travis CI | GitHub Actions |
GitHub Stars | 147 | 45 | 14 |
Static analysis | golangci-lint, luacheck | golint | golangci-lint |
Packaging | go get | go get | go get |
Code coverage | Yes | No | No |
msgpack driver | vmihailenco/msgpack/v2 or vmihailenco/msgpack/v5 | tinylib/msgp | vmihailenco/msgpack/v5 |
Async work | Yes | Yes | Yes |
Schema reload | Yes (manual pull) | Yes (manual pull) | Yes (manual pull) |
Space / index names | Yes | Yes | Yes |
Tuples as structures | Yes (structure and marshall functions must be predefined in Go code) | No | Yes (structure and marshall functions must be predefined in Go code) |
Access tuple fields by names | Only if marshalled to structure | No | Only if marshalled to structure |
SQL support | Yes | No (#18, closed) | No |
Interactive transactions | Yes | No | No |
Varbinary support | Yes (with in-built language tools) | Yes (with in-built language tools) | Yes (decodes to string by default, see #6) |
UUID support | Yes | No | No |
Decimal support | Yes | No | No |
EXT_ERROR support | Yes | No | No |
Datetime support | Yes | No | No |
box.session.push() responses | Yes | No (#21) | Yes |
Session settings | Yes | No | No |
Graceful shutdown | Yes | No | No |
IPROTO_ID (feature discovering) | Yes | No | No |
tarantool/crud support | No | No | No |
Connection pool | Yes (round-robin failover, no balancing) | No | No |
Transparent reconnecting | Yes (see comments in #129) | No (handle reconnects explicitly, refer to #11) | Yes (see comments in #7) |
Transparent request retrying | No | No | No |
Watchers | Yes | No | No |
Pagination | Yes | No | No |
Language features | context | context | context |
Miscellaneous | Supports tarantool/queue API | Can mimic a Tarantool instance (also as replica). Provides instrumentation for reading snapshot and xlog files via snapio module. Implements unpacking of query structs if you want to implement your own iproto proxy | API is experimental and breaking changes may happen |