Featured image of post

TiDB is a distributed SQL database. Inspired by the design of Google F1.

Introduction

TiDB is a distributed SQL database that brings the scalability of NoSQL databases to the world of relational data. With an impressive 39,845 stars on GitHub, this open-source project from PingCAP has become a cornerstone in the modern database landscape. TiDB is inspired by Google’s F1 database and provides horizontal scalability, strong consistency, and high availability—all while maintaining full compatibility with the MySQL protocol.

Developers should care about TiDB because it solves the fundamental problem of scaling relational databases. Traditional SQL databases struggle with horizontal scaling, often requiring complex sharding strategies or expensive hardware upgrades. TiDB eliminates these pain points by automatically partitioning data across multiple nodes while maintaining ACID transactions and strong consistency guarantees. This means you can start small and scale seamlessly as your application grows, without rewriting your SQL queries or changing your application code.

The real-world use cases for TiDB are extensive. E-commerce platforms use it to handle massive transaction volumes during peak shopping seasons. Financial institutions leverage its strong consistency for critical transaction processing. Real-time analytics companies use TiDB’s HTAP (Hybrid Transactional and Analytical Processing) capabilities to run complex queries on fresh data without impacting transactional workloads. Gaming companies rely on it for leaderboards and user data that need to scale rapidly. Essentially, any application that needs the reliability of SQL with the scalability of NoSQL can benefit from TiDB.

Key Features

Horizontal Scalability is perhaps TiDB’s most distinguishing feature. Unlike traditional databases that require vertical scaling (bigger machines), TiDB can scale out by simply adding more nodes to the cluster. The system automatically rebalances data across nodes, ensuring optimal performance as your dataset grows. This feature alone can save organizations millions in infrastructure costs and eliminate the dreaded “we need a bigger database server” conversations.

MySQL Compatibility is a game-changer for teams transitioning from MySQL. TiDB speaks the MySQL protocol natively, meaning you can use existing MySQL client libraries, connectors, and tools without modification. Your application code, including SQL queries, remains unchanged. This compatibility extends to most MySQL syntax and features, making migration as simple as changing the connection string. For organizations with legacy MySQL applications, this feature eliminates the risk and complexity typically associated with database migrations.

ACID Transactions ensure data integrity even at massive scale. TiDB supports distributed transactions with snapshot isolation and distributed ACID compliance. This means you get the same transactional guarantees as traditional databases, even when your data spans multiple machines. The system uses a two-phase commit protocol and multi-version concurrency control (MVCC) to maintain consistency, making it suitable for financial applications and other use cases where data integrity is paramount.

High Availability is built into TiDB’s architecture through automatic failover and data replication. Data is replicated across multiple nodes using the Raft consensus algorithm, ensuring that the system can tolerate node failures without data loss. If a node goes down, the system automatically promotes a replica to maintain service availability. This architecture provides both high availability and disaster recovery capabilities without requiring manual intervention or complex failover procedures.

HTAP Capabilities set TiDB apart from traditional databases. The system includes TiFlash, a columnar storage engine that runs alongside the row-based TiKV storage. This allows TiDB to handle both transactional workloads (OLTP) and analytical queries (OLAP) simultaneously without impacting each other. You can run complex analytical queries on fresh transactional data without creating separate data warehouses or ETL pipelines, dramatically simplifying your data architecture.

Cloud-Native Design makes TiDB ideal for modern infrastructure. The database is designed to run on Kubernetes and integrates seamlessly with cloud platforms. TiDB Operator automates deployment, scaling, and management tasks, while the system’s architecture naturally supports multi-cloud and hybrid cloud deployments. This cloud-native approach reduces operational overhead and enables DevOps teams to manage TiDB clusters using familiar tools and practices.

Installation and Setup

To install TiDB, you’ll need Go 1.16 or later and Docker installed on your system. The recommended approach is to use TiUP, TiDB’s official deployment tool:

1curl --proto '=https' --tlsv1.2 -sSf https://tiup-mirrors.pingcap.com/install.sh | sh

After installation, restart your terminal or run:

1source ~/.bash_profile

Verify the installation:

1tiup --version

To start a local TiDB cluster for development:

1tiup playground

This command starts a complete TiDB cluster with TiDB server, TiKV (storage), and PD (placement driver) components. By default, it creates:

  • TiDB server on port 4000
  • MySQL protocol port 4000
  • Dashboard on port 2379
  • PD on port 2379

You can connect to your local TiDB instance using any MySQL client:

1mysql -h 127.0.0.1 -P 4000 -u root

The root user has no password by default in the playground environment. Once connected, you can run standard MySQL commands to verify everything is working:

1SHOW DATABASES;
2CREATE DATABASE test_db;
3USE test_db;
4CREATE TABLE users (id INT PRIMARY KEY, name VARCHAR(50));
5INSERT INTO users VALUES (1, 'John Doe');
6SELECT * FROM users;

Basic Usage

Here’s a minimal “Hello World” example that demonstrates connecting to TiDB and performing basic operations:

 1package main
 2
 3import (
 4    "context"
 5    "database/sql"
 6    "fmt"
 7    _ "github.com/go-sql-driver/mysql"
 8)
 9
10func main() {
11    // Connect to TiDB using MySQL driver
12    dsn := "root:@tcp(127.0.0.1:4000)/test"
13    db, err := sql.Open("mysql", dsn)
14    if err != nil {
15        panic(err)
16    }
17    defer db.Close()
18
19    // Create table
20    _, err = db.ExecContext(context.Background(), `
21        CREATE TABLE IF NOT EXISTS hello (
22            id BIGINT PRIMARY KEY AUTO_INCREMENT,
23            message VARCHAR(100) NOT NULL
24        )
25    `)
26    if err != nil {
27        panic(err)
28    }
29
30    // Insert data
31    result, err := db.ExecContext(context.Background(), 
32        "INSERT INTO hello (message) VALUES (?)", "Hello, TiDB!")
33    if err != nil {
34        panic(err)
35    }
36
37    // Get the inserted ID
38    id, err := result.LastInsertId()
39    if err != nil {
40        panic(err)
41    }
42
43    // Query data
44    var message string
45    err = db.QueryRowContext(context.Background(), 
46        "SELECT message FROM hello WHERE id = ?", id).
47        Scan(&message)
48    if err != nil {
49        panic(err)
50    }
51
52    fmt.Printf("Inserted message: %s\n", message)
53}

Expected output:

1Inserted message: Hello, TiDB!

This example demonstrates the basic pattern for working with TiDB: connect using the MySQL driver, execute SQL statements, handle errors, and process results. The code uses context for cancellation support and follows Go’s error handling conventions. The database/sql package provides a familiar interface for developers already comfortable with Go’s database patterns.

Real-World Examples

Example 1: E-Commerce Order Processing System

This comprehensive example demonstrates a realistic e-commerce order processing system using TiDB. It includes transaction management, inventory checking, and order creation with proper error handling.

 1package main
 2
 3import (
 4    "context"
 5    "database/sql"
 6    "fmt"
 7    "log"
 8    "time"
 9
10    _ "github.com/go-sql-driver/mysql"
11)
12
13type Product struct {
14    ID          int64
15    Name        string
16    Price       float64
17    Stock       int
18    Description string
19}
20
21type Order struct {
22    ID       int64
23    UserID   int64
24    Status   string
25    Created  time.Time
26    Items    []OrderItem
27}
28
29type OrderItem struct {
30    ProductID int64
31    Quantity  int
32    Price     float64
33}
34
35type OrderService struct {
36    db *sql.DB
37}
38
39func NewOrderService(dsn string) (*OrderService, error) {
40    db, err := sql.Open("mysql", dsn)
41    if err != nil {
42        return nil, err
43    }
44
45    // Test connection
46    if err := db.Ping(); err != nil {
47        db.Close()
48        return nil, err
49    }
50
51    return &OrderService{db: db}, nil
52}
53
54func (s *OrderService) CreateOrder(ctx context.Context, userID int64, items []OrderItem) (*Order, error) {
55    // Start transaction
56    tx, err := s.db.BeginTx(ctx, &sql.TxOptions{Isolation: sql.LevelSerializable})
57    if err != nil {
58        return nil, err
59    }
60
61    var order Order
62    order.UserID = userID
63    order.Status = "pending"
64    order.Created = time.Now()
65    order.Items = items
66
67    //

Photo by Rahul Mishra on Unsplash

comments powered by Disqus
Built with Hugo
Theme Stack designed by Jimmy