9.1 Introduction to Databases
Table of Contents
Why Backends Need Databases
When you build a backend, you almost always need a place to store data so you can use it later. A database is that place.
Some typical things a backend stores:
- Users and passwords (securely hashed)
- Blog posts, comments, likes
- Products, orders, payments
- Logs and metrics
- Configuration and feature flags
You could store data in files like data.json, but this quickly becomes a problem:
- How do you search efficiently?
- How do you update one item without corrupting the file?
- How do you handle multiple users writing at the same time?
- How do you prevent data loss if your app crashes during a write?
Databases solve these problems. They are specialized systems designed to:
- Store data safely and reliably
- Answer questions (queries) quickly
- Handle many users at the same time
- Keep data consistent and recoverable
Key idea: A database is a system that stores data in a structured way, lets many users and applications access it at the same time, and provides tools to query, update, and protect that data.
In backend development, you usually do not build your own database from scratch. You use an existing database engine such as PostgreSQL, MySQL, or MongoDB.
Database vs File Storage
Many beginners wonder: “Why not just use files?”
Simple file storage example
Imagine a simple blog application that stores posts in a JSON file:
[
{
"id": 1,
"title": "Hello world",
"content": "My first post",
"author": "alice",
"created_at": "2026-08-27T12:00:00Z"
},
{
"id": 2,
"title": "Second post",
"content": "More content",
"author": "bob",
"created_at": "2026-08-27T13:00:00Z"
}
]
If you want to find all posts by alice, your backend would:
- Read the whole file into memory.
- Loop over all items.
- Filter items where
author == "alice".
This is fine for 10 posts, maybe 1000 posts, but not for millions.
File storage problems
With pure file storage, you must handle everything yourself:
- Searching
- You must write code to scan data for every query.
- There are no built-in indexes to speed up lookups.
- Updating a record
- You must read the file, modify the data in memory, then write the whole file back.
- A crash during write can leave the file corrupted.
- Concurrent access
- Two users updating at the same time can overwrite each other’s changes.
- You need to implement locking or versioning by hand.
- Backups and recovery
- You must create backup copies manually.
- Restoring from partial or corrupted files is tricky.
How databases improve this
Databases provide:
- Query language: For example SQL, to express “Give me all posts by alice created after yesterday.”
- Indexes: Special data structures that make lookups fast.
- Transactions: Group operations that either all succeed or all fail.
- Concurrency control: Multiple clients can read and write safely.
- Backups and replication: Built-in or supported tools to copy and restore data.
So you, as a backend developer, can focus on business logic, not on reinventing safe storage.
Types of Data and Databases
Different applications work with different types of data, and different databases are optimized for different styles.
Structured vs semi-structured vs unstructured data
| Type | Example | Typical storage |
|---|---|---|
| Structured | Users with name, email, created_at | Relational databases (PostgreSQL, MySQL) |
| Semi-structured | JSON API responses, settings documents | Document databases (MongoDB), JSON columns |
| Unstructured | Images, videos, PDFs | Object storage (S3), file storage |
As a backend developer you will often:
- Store structured data in a relational database.
- Store large files in an object storage service.
- Maybe store semi-structured data in a document store or in JSON columns of a relational DB.
This chapter focuses on the core database concepts, not on choosing a database yet.
Core Concepts: Database, Table, Row, Column
At a very high level, a typical relational database system has:
- A database server: The program that runs (for example PostgreSQL).
- One or more databases: Logical containers inside the server.
- Inside each database, you have tables.
- Tables contain rows (also called records), and each row has columns (also called fields).
You will study tables, rows, and columns more deeply in later chapters. For now, you only need an intuitive picture.
Simple example
Imagine a database for a task management app. It might have tables like:
userstasksprojects
The users table could look like this conceptually:
| id | name | created_at | |
|---|---|---|---|
| 1 | alice@example.com | Alice | 2026-08-27 10:00:00 UTC |
| 2 | bob@example.com | Bob | 2026-08-27 10:05:00 UTC |
In code, this concept maps to a Python dictionary or JSON, but in a database it is a row in a table.
Visual analogy
Think of:
- A table as a spreadsheet sheet.
- Columns as the vertical labeled sections like
email,name. - Rows as individual entries like “Alice”.
But databases are much more powerful than spreadsheets:
- They can handle millions or billions of rows.
- They can be accessed by many clients simultaneously.
- They have transactions, indexing, and query languages.
How Backends Talk to Databases
Your backend application is usually a separate program that connects to a database server over the network.
Connection basics
To connect, the backend needs:
- Host: Where the database server runs, for example
localhostordb.example.com. - Port: A number indicating where the database listens, for example
5432for PostgreSQL. - Database name: For example
task_manager. - User and password: For authentication.
In Python, a very simplified PostgreSQL connection might look like:
import psycopg2
conn = psycopg2.connect(
host="localhost",
port=5432,
dbname="task_manager",
user="app_user",
password="secret-password"
)You will normally hide these values in environment variables, not hard-code them, but this shows the idea.
Once connected, the backend can:
- Send a query to read data.
- Send a command to insert, update, or delete data.
Query example
Imagine we want all tasks for user with ID 1:
cursor = conn.cursor()
cursor.execute("SELECT id, title, completed FROM tasks WHERE user_id = %s", (1,))
rows = cursor.fetchall()The idea is:
- The backend forms a query.
- The database parses and executes it.
- The database returns the results to the backend.
You will learn the SQL language and ORMs later. At this stage just remember: the backend talks to the database using a protocol and a query language, most often SQL.
What Databases Do for Your Backend
Databases offer several important properties that directly affect how you design your backend.
Reliability and durability
If your server restarts, you do not want to lose all data.
Databases typically guarantee that once data is committed, it will survive crashes and restarts, as long as disk storage is intact.
For example:
- Your user registers.
- You store the user in the database.
- The server crashes right after.
- When you restart the server, the user is still there.
Consistency and constraints
Databases can enforce rules about your data:
- Emails must be unique.
- A task must belong to a valid user.
- A column cannot be empty.
These rules are called constraints and help keep your data valid. You will study them in detail in a separate chapter.
Your backend can rely on the database to prevent certain invalid states, which simplifies your code.
Concurrency
Many clients access your backend at the same time. They might:
- Create users at the same moment.
- Update the same task simultaneously.
- Read data while others write.
The database manages concurrency so that operations do not corrupt data. For example, it ensures that:
- Two users inserting a record at the same time both succeed.
- Conflicting updates are handled according to rules (like locking or versioning).
As a backend developer, you need to understand that:
- Databases can handle multiple connections at once.
- But there are limits on how many connections and queries they can handle efficiently.
- You may use connection pools to reuse connections.
Transactions
A transaction groups a set of operations into a single logical unit. Either all operations succeed, or none of them do.
Example:
- Step 1: Create an order in the
orderstable. - Step 2: Decrease product stock in
productstable. - Step 3: Insert order items in
order_itemstable.
You want either all three steps to succeed, or if any fails, you want none of them to be saved, so your data does not get into a broken state.
In Python pseudocode:
try:
cursor.execute("BEGIN")
cursor.execute("INSERT INTO orders (...) VALUES (...);")
cursor.execute("UPDATE products SET stock = stock - 1 WHERE id = ...;")
cursor.execute("INSERT INTO order_items (...) VALUES (...);")
cursor.execute("COMMIT")
except Exception:
cursor.execute("ROLLBACK")
raiseYou will learn more about transactions and ACID properties in later chapters, but the key point is that databases can group operations safely.
Important: Use transactions when you need multiple related changes to be applied together, so your data never ends up in a half-updated state.
Logical vs Physical View of Data
As a backend developer, you mostly work with the logical view of the data, not how bytes are stored on disk.
Logical view
Examples of questions you ask:
- “What tables do I need?”
- “Which columns should be in this table?”
- “How do I link users to tasks?”
You think of data in terms of:
- Tables and columns.
- Relationships between tables.
- Queries that answer business questions.
Physical view
The database internally deals with:
- How rows are stored on disk.
- Which indexes to use for a query.
- How to cache frequently used data in memory.
- How to write logs for crash recovery.
You rarely control these details directly, although you might tune them for performance later.
The separation is helpful:
- You focus on modeling your business problem.
- The database focuses on storage and performance.
Examples of Common Backend Data Models
To make the idea of a database concrete, here are some simple models you might build as a beginner backend developer.
User and task model
For a task management API, you might have:
users table
| Column | Type | Notes |
|---|---|---|
| id | integer | Unique identifier |
| text | Must be unique | |
| password | text | Hashed password |
| created_at | timestamp | When the user registered |
tasks table
| Column | Type | Notes |
|---|---|---|
| id | integer | Unique identifier |
| user_id | integer | Which user owns the task |
| title | text | Task title |
| completed | boolean | True or false |
| created_at | timestamp | When the task was created |
Your backend would:
- Create a new row in
userswhen someone registers. - Create new rows in
taskswhen they add tasks. - Query
taskswhereuser_idis the current user to list their tasks.
You will learn more about relationships like user_id in dedicated chapters.
Blog model
For a simple blog, you might design:
userstable, similar to the previous example.poststable withauthor_id,title,content,published_at.commentstable withpost_id,author_id,content.
Your backend:
- Uses routes like
GET /poststo read from thepoststable. - Uses
POST /poststo insert intoposts. - Uses
GET /posts/{id}/commentsto query thecommentstable.
These models show how database tables map naturally to backend API endpoints.
How Databases Fit into a Backend System
It is useful to see where the database sits in the whole architecture.
A typical web backend has:
- Client
Web browser, mobile app, or another service. - Backend application
Your code, for example a FastAPI app running on a server. - Database server
PostgreSQL, MySQL, or another database that stores persistent data.
Communication flow:
- Client sends a request to your backend, for example
POST /tasks. - Backend receives the request, validates input.
- Backend sends a query to the database to insert a new task row.
- Database stores the data and returns a result.
- Backend sends a response back to the client.
In diagram form:
| Step | Actor | Action |
|---|---|---|
| 1 | Client | Sends HTTP request |
| 2 | Backend | Processes request |
| 3 | Backend → DB | Executes query (insert / select) |
| 4 | DB → Backend | Returns rows / success status |
| 5 | Backend → Client | Sends HTTP response |
The database is a separate component. It might run:
- On the same machine as the backend (development).
- On a dedicated server or cloud service (production).
Choosing a Database as a Beginner
You will later study the differences between relational and NoSQL databases. For now, it is useful to know what beginners usually start with.
Most backend tutorials and real-world APIs use:
- A relational database, for example PostgreSQL.
- SQL as the query language.
- An ORM (Object Relational Mapper) to interact with the database using code instead of writing raw SQL everywhere.
Common beginner choices:
| Purpose | Popular choice |
|---|---|
| Main application data | PostgreSQL |
| Simple dev / experiments | SQLite |
| Caching / ephemeral data | Redis |
For this course, you will usually see PostgreSQL as the main example database.
Practical advice: As a beginner backend developer, focus on learning one relational database (like PostgreSQL) and SQL well before exploring many other database types.
Summary
In this chapter you learned:
- What a database is and why backends need one.
- Why simple file storage is not enough for real applications.
- Basic concepts like database, table, row, column.
- How backends connect to and query databases.
- The roles of reliability, consistency, concurrency, and transactions.
- How data models for users, tasks, posts, and comments look in a database.
- Where the database fits in the overall backend architecture.
- Why relational databases, especially PostgreSQL, are a solid starting point.
In the next chapters you will dive deeper into database types, structures, relationships, and how to design efficient and reliable schemas for your backend applications.
Views: 7
KAHIBARO