How to Implement Read Replicas and Write Splitting in Go

Go does not have built-in support for read replicas or write splitting; you must implement this logic using a database connection pool and a custom routing layer. Use the `database/sql` package to manage separate connection pools for your primary (write) and replica (read) databases, then route quer

How to Implement Read Replicas and Write Splitting in Go

Go does not have built-in support for read replicas or write splitting; you must implement this logic using a database connection pool and a custom routing layer. Use the database/sql package to manage separate connection pools for your primary (write) and replica (read) databases, then route queries based on the operation type.

package main

import (
	"database/sql"
	"context"
	"fmt"
	"log"
)

var writeDB *sql.DB // Primary database
var readDB *sql.DB  // Read replica database

func init() {
	var err error
	writeDB, err = sql.Open("postgres", "postgres://user:pass@primary:5432/db")
	if err != nil {
		log.Fatalf("failed to open write DB: %v", err)
	}
	if err = writeDB.PingContext(context.Background()); err != nil {
		log.Fatalf("failed to ping write DB: %v", err)
	}

	readDB, err = sql.Open("postgres", "postgres://user:pass@replica:5432/db")
	if err != nil {
		log.Fatalf("failed to open read DB: %v", err)
	}
	if err = readDB.PingContext(context.Background()); err != nil {
		log.Fatalf("failed to ping read DB: %v", err)
	}
}

func CreateUser(ctx context.Context, name string) error {
	_, err := writeDB.ExecContext(ctx, "INSERT INTO users (name) VALUES ($1)", name)
	return err
}

func GetUsers(ctx context.Context) ([]string, error) {
	rows, err := readDB.QueryContext(ctx, "SELECT name FROM users")
	if err != nil {
		return nil, err
	}
	defer rows.Close()
	var names []string
	for rows.Next() {
		var name string
		if err := rows.Scan(&name); err != nil {
			return nil, err
		}
		names = append(names, name)
	}
	return names, nil
}

func main() {
	ctx := context.Background()
	
	if err := CreateUser(ctx, "Alice"); err != nil {
		log.Fatalf("failed to create user: %v", err)
	}
	
	users, err := GetUsers(ctx)
	if err != nil {
		log.Fatalf("failed to get users: %v", err)
	}
	
	fmt.Printf("Users: %v\n", users)
}