Surveying the Go Database Landscape

Surveying Go Database Landscape

Databases are at the heart of most business and web apps. If you’re considering using Go for your next project, one of the first things you’re going to look at is whether or not it has an integration for your current database (DB).

Go has a thriving package ecosystem and highly engaged community. Thanks to this vibrant development ecosystem, there are solutions that exist for almost every flavour of database. If you’re new to Go, it can be difficult to wrap your head around the wide array of options that are available. In this post, we’ll take a brief 10,000 ft view of the various database integrations currently available in Go to give you a sense of what’s out there and how they can work with your existing systems.

Databases compatible with database/sql

SQL based relational databases are the industry standard, especially in large enterprises. Go has a large number of packages for SQL based databases, most of which have standardized around the database/sql interface. Using any package that implements this interface allows you to write your database code once and swap out the database driver if you switch between database types.

While this doesn’t provide a complete abstraction of your database layer like an ORM (Object Relational Mapping) tool, it does provide a layer of abstraction from the database driver and a level of consistency in the interface used to access the DB.

Connecting using the database/sql interface is straightforward:

import (
    "database/sql"
    _ "github.com/go-sql-driver/mysql"  // or postgres, sqlite3, etc.
)
db, err := sql.Open("mysql", "user:pass@/yourdb") 
// sql.Open does not establish a connection, ping the DB to test
err = db.Ping()

Tip: Notice that you use the ‘_’ in the import statement since you only need to import the side-effects of the driver to register it with database/sql rather than all of the package exports.

Native Go database drivers using the database/sql interface are available for major databases like Postgres and MySQL, but some drivers like the popular Sqlite3 driver are still C based which means you’ll need gcc installed if you want to update or develop using those packages. This dependency on a C compiler is one of the reasons to prefer a pure Go implementation of your DB driver.

Enterprise Relational database management systems (RDBMS) and database/sql

If you’re a large organization exploring Go as an option, you’re likely concerned as to whether or not it can interface with your existing RDBMS like Oracle or DB2. Thankfully, there are interface options for pretty much all major RDBMS systems, but not all of them offer native Go drivers.

For some large systems like Microsoft SQL Server there are actively maintained pure Go database drivers. However, many popular systems like Oracle, DB2 or SAP’s SQL Anywhere currently only have C API wrapper interfaces available.

Extensions to database/sql

There are a growing number of extensions to the database/sql interface that provide expanded functionality and convenience. A popular package like sqlx provides a number of handy extensions like the ability to map results to structs or slices, or shortcut methods like .Select or .Get to simplify queries.

// Sqlx simplifies many common actions. Here we open, connect and error check in one statement
db = sqlx.MustConnect("mysql", "user:pass@/yourdb")

Other packages in this space like dbr start to provide ORM-like functionality offering improved performance and query-builder syntax that allows you to easily build up queries without writing SQL directly.

// Using query-builder syntax to do a Select instead of raw SQL
db.Select("id", "name").From("customers").Where("id = ?", 1).Load(&customer)

Projects like squirrel are purely query-builders, whereas something like structable moves towards being a more fully-featured ORM.

There is an emerging set of ORM packages that look to replicate the power and speed of tools like Ruby’s ActiveRecord. While none of these has clearly established itself as the standard, there are packages like GORM that can get you started.

NoSQL Databases

With NoSQL database solutions gaining in popularity and occupying a larger portion of the market it’s not surprising that the Go community has an equal amount of support for these systems. There isn’t a standardized interface for these, so you’ll have to use the driver directly from your code.

Some popular NoSQL database solutions like MongoDB and Couchbase have well-maintained Go bindings like mgo and gocb, while others like CouchDB have a number of less-maintained bindings with no clear leader.

Even though you’re working with the driver directly, connecting using mgo is extremely straightforward. mgo uses the concept of sessions to manage database connections. You can initiate a session with a single line:

session, err := mgo.Dial(myDBServerURL)

From there, there is a very simple API allowing you to access collections and run queries to retrieve documents.

Finally, Redis is a popular key/value store and has a number of packages that provide an interface and tools for working with Redis. go-redis and redigo are the most actively maintained packages for Redis support. Both support similar interfaces with extremely straightforward APIs for Getting/Setting values within the key/value store.

Big Data and Microservices

Go’s built-in concurrency makes it a great choice for various large-scale applications, especially those involving Big Data processing and microservices architecture. For these use cases, you’re looking for DB solutions that not only play nice with a number of different interacting systems, but scale well horizontally.

The popular clustered database solution Cassandra has a number of Go clients with a variety of feature sets. Packages like gocql provide a simple native Go interface that makes interacting with clusters of DBs straightforward:

    // Connect to a Cassandra cluster
    cluster := gocql.NewCluster("192.168.1.1", "192.168.1.2", "192.168.1.3")

Once connected, gocql uses a Session concept for managing interaction with the cluster.

Another Apache project, Kafka, is a time-series database which excels in real-time monitoring, metrics, and messaging. It has a pure Go interface in the sarama package, which provides an extensive API to capture its many use-cases.

MongoDB (as outlined above) is also a popular database for large data sets, and Go also supports a number of message brokers like RabbitMQ (ampq) for linking together numerous different services.

Native Go Databases

Besides the multitude of clients available for existing database solutions, there are also a growing number of native Go databases that offer amazing performance and features. For those working inside the Go ecosystem it’s an added bonus to be able to remove a dependency on other non-Go communities.

InfluxDB is a great choice for real-time monitoring, sensor data or other operational data. It is written in Go, provides an SQL-like interface and is designed to deal with time-series data points. It uses an HTTP API which means accessing it from your existing code is extremely simple.

TiDB is another database system written in Go that aims to combine the best of SQL and NoSQL to provide a horizontally scalable transaction based DB with an SQL interface.

Finally, Bolt offers a simple, highly performant embedded key/value store written in Go. For users who don’t require the infrastructure or complexity of a full relational DB, Bolt’s simplicity and speed make it a great option.

A Healthy Future

With the increased adoption of Go, it’s likely that we’ll see standardization in a number of areas when it comes to packages and interfaces. Go’s unique features make it extremely well-suited to database applications, especially on the scale that many Enterprise developers are accustomed to. With many of the packages already in wide scale production use today, there is a wealth of options available that you can choose for your next project.