Guide to Using PostgreSQL with Go: Installation and Examples
Connecting to a PostgreSQL database in Go is a common requirement for many applications. Go provides robust support for interacting with databases, including PostgreSQL, through libraries such as database/sql
in combination with a PostgreSQL driver like pgx
or lib/pq
. Below is a guide for setting up and using PostgreSQL in a Go application.
Setting Up
- Install PostgreSQL Driver: You can use
pgx
(recommended for its performance and features) orlib/pq
. Here, we’ll usepgx
.
go get github.com/jackc/pgx/v4/pgxpool
- Import Required Packages:
package main
import (
"context"
"fmt"
"log"
"github.com/jackc/pgx/v4/pgxpool"
)
Connecting to PostgreSQL
Here's a basic example of how to connect to a PostgreSQL database using pgx
:
package main
import (
"context"
"fmt"
"log"
"os"
"github.com/jackc/pgx/v4/pgxpool"
)
func main() {
// Database connection string (adjust as needed)
connString := "postgres://username:password@localhost:5432/mydb"
// Create a connection pool
dbpool, err := pgxpool.Connect(context.Background(), connString)
if err != nil {
log.Fatalf("Unable to connect to database: %v\n", err)
}
defer dbpool.Close()
// Check if the connection works
var greeting string
err = dbpool.QueryRow(context.Background(), "SELECT 'Hello, world!'").Scan(&greeting)
if err != nil {
log.Fatalf("QueryRow failed: %v\n", err)
}
fmt.Println(greeting)
}
Executing Queries
Creating Tables
func createTable(dbpool *pgxpool.Pool) {
createTableSQL := `
CREATE TABLE IF NOT EXISTS users (
id SERIAL PRIMARY KEY,
name TEXT NOT NULL,
age INT NOT NULL
);`
_, err := dbpool.Exec(context.Background(), createTableSQL)
if err != nil {
log.Fatalf("Failed to create table: %v\n", err)
}
}
Inserting Data
func insertUser(dbpool *pgxpool.Pool, name string, age int) {
insertSQL := `INSERT INTO users (name, age) VALUES ($1, $2) RETURNING id`
var id int
err := dbpool.QueryRow(context.Background(), insertSQL, name, age).Scan(&id)
if err != nil {
log.Fatalf("Failed to insert user: %v\n", err)
}
fmt.Printf("Inserted user with ID %d\n", id)
}
Querying Data
func getUsers(dbpool *pgxpool.Pool) {
rows, err := dbpool.Query(context.Background(), `SELECT id, name, age FROM users`)
if err != nil {
log.Fatalf("Failed to execute query: %v\n", err)
}
defer rows.Close()
for rows.Next() {
var id int
var name string
var age int
err = rows.Scan(&id, &name, &age)
if err != nil {
log.Fatalf("Failed to scan row: %v\n", err)
}
fmt.Printf("ID: %d, Name: %s, Age: %d\n", id, name, age)
}
if rows.Err() != nil {
log.Fatalf("Row iteration error: %v\n", rows.Err())
}
}
Example Full Program
Combining all the above components into a complete program:
package main
import (
"context"
"fmt"
"log"
"github.com/jackc/pgx/v4/pgxpool"
)
func main() {
// Database connection string (adjust as needed)
connString := "postgres://username:password@localhost:5432/mydb"
// Create a connection pool
dbpool, err := pgxpool.Connect(context.Background(), connString)
if err != nil {
log.Fatalf("Unable to connect to database: %v\n", err)
}
defer dbpool.Close()
// Create table
createTable(dbpool)
// Insert users
insertUser(dbpool, "Alice", 30)
insertUser(dbpool, "Bob", 25)
// Get and print users
getUsers(dbpool)
}
func createTable(dbpool *pgxpool.Pool) {
createTableSQL := `
CREATE TABLE IF NOT EXISTS users (
id SERIAL PRIMARY KEY,
name TEXT NOT NULL,
age INT NOT NULL
);`
_, err := dbpool.Exec(context.Background(), createTableSQL)
if err != nil {
log.Fatalf("Failed to create table: %v\n", err)
}
}
func insertUser(dbpool *pgxpool.Pool, name string, age int) {
insertSQL := `INSERT INTO users (name, age) VALUES ($1, $2) RETURNING id`
var id int
err := dbpool.QueryRow(context.Background(), insertSQL, name, age).Scan(&id)
if err != nil {
log.Fatalf("Failed to insert user: %v\n", err)
}
fmt.Printf("Inserted user with ID %d\n", id)
}
func getUsers(dbpool *pgxpool.Pool) {
rows, err := dbpool.Query(context.Background(), `SELECT id, name, age FROM users`)
if err != nil {
log.Fatalf("Failed to execute query: %v\n", err)
}
defer rows.Close()
for rows.Next() {
var id int
var name string
var age int
err = rows.Scan(&id, &name, &age)
if err != nil {
log.Fatalf("Failed to scan row: %v\n", err)
}
fmt.Printf("ID: %d, Name: %s, Age: %d\n", id, name, age)
}
if rows.Err() != nil {
log.Fatalf("Row iteration error: %v\n", rows.Err())
}
}
Conclusion
This guide provides a basic setup for interacting with a PostgreSQL database in Go using the pgx
package. For more advanced use cases, consider leveraging additional features of pgx
, such as connection pooling, prepared statements, and transaction management. The examples above should provide a solid foundation for building more complex database interactions in your Go applications.