Getting Started with SQL Transactions in PostgreSQL
Tags: databasedevelopment, database, sql, programming
Published: 2024-04-19 20:06:42

---
title: Getting Started with SQL Transactions in PostgreSQL
published: true
date: 2024-04-14 11:01:41 UTC
tags: databasedevelopment,database,sql,programming
canonical_url: https://antondevtips.com/blog/get-started-with-sql-transactions-in-postgresql
---

### Get Started with SQL Transactions in PostgreSQL

### Introduction to SQL Transactions

**SQL transactions** are essential for ensuring data integrity and consistency in database operations. They allow multiple SQL commands to be executed as a single, atomic operation, meaning either all commands are successfully executed, or none are, ensuring the database remains in a consistent state. This blog post introduces the concept of **SQL transactions** , with a focus on their implementation in PostgreSQL, using a practical database model as an example.

A **transaction** in SQL is a sequence of one or more SQL operations performed as a single unit. Transactions follow the **ACID principles** :

- **Atomicity**  — ensures that all operations within a transaction are completed successfully; if at least one operation failed — the transaction is aborted.
- **Consistency**  — guarantees that a transaction takes the database from one valid state to another.
- **Isolation**  — ensures that the concurrent execution of transactions leaves the database in the same state as if the transactions were executed one after another.
- **Durability**  — ensures that once a transaction has been committed, it will remain so, even in the event of a power loss, crashes, or errors.

> _All SQL queries from this blog post were tested in the_ **_Postgres database_** _. While the same SQL syntax can be used in other databases._

> All SQL queries from this blog post were tested in the Postgres database. While the same SQL syntax can be used in other databases.

### How to Create and Commit a Transaction

To start a **transaction** in PostgreSQL, use the BEGIN command. All SQL operations that come after the BEGIN command - are a part of the transaction until it's either **committed** or **rolled**  back.

- **COMMIT**  — ensures that all changes made to the database are persisted (saved).
- **ROLLBACK**  — ensures that all changes made to the database are rejected (not saved).

Here is the general syntax of creating a SQL **transaction** :

```sql
-- Start transaction
BEGIN;

COMMIT;
-- or ROLLBACK:
```

All databases including PostgreSQL has a feature called **transaction isolation levels** , which control how concurrent transaction changes are visible to each other. To set an isolation level, you can use the SET TRANSACTION command right after BEGIN statement:

```sql
BEGIN;
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;

-- Transaction operations here...

COMMIT;
```

Transaction isolation levels is a big topic and deserves a separate blog post.

Within a transaction, you can perform various operations such as selecting, inserting, updating, or deleting records across multiple tables.

If any operation within the transaction fails or if you detect an error in your logic, you can undo all operations within the transaction using the ROLLBACK command. This reverts the database to its state before the transaction began and all changes are not saved into the database.

### Real-World Use Case with Transactions

Let’s set up a database in PostgreSQL that includes tables for customers, products, orders, and order\_details:

```sql
CREATE TABLE customers (
    id INT PRIMARY KEY GENERATED ALWAYS AS IDENTITY,
    name VARCHAR(255),
    phone VARCHAR(20),
    email VARCHAR(255),
    is_active BOOLEAN
);

CREATE TABLE products (
    id INT PRIMARY KEY GENERATED ALWAYS AS IDENTITY,
    name VARCHAR(255),
    price DECIMAL
);

CREATE TABLE orders (
    id INT PRIMARY KEY GENERATED ALWAYS AS IDENTITY,
    customer_id INT,
    date DATE,
    FOREIGN KEY (customer_id) REFERENCES customers(id)
);

CREATE TABLE order_details (
    id INT PRIMARY KEY GENERATED ALWAYS AS IDENTITY,
    order_id INT,
    product_id INT,
    quantity INT,
    price DECIMAL(10, 2),
    FOREIGN KEY (order_id) REFERENCES orders(id),
    FOREIGN KEY (product_id) REFERENCES products(id)
);
```

Imagine an online store where you order a product and register in a single step. We can create a new customer, create an order, and add order details into the database as a single transaction, ensuring data integrity. Here’s an example of such a transaction:

```sql
-- Start transaction
BEGIN;

WITH new_customer AS (
    -- Return a created customer id
    INSERT INTO customers (name, phone, email, is_active)
    VALUES ('Jack Sparrow', '123-456-7890', 'captain@jack.com', TRUE)
    RETURNING id
),
new_order AS (
    -- Use the saved customer ID to create a new order
    -- Return a created order id
    INSERT INTO orders (customer_id, date)
    VALUES ((SELECT id FROM new_customer), '2024-02-20')
    RETURNING id
),
selected_product AS (
    SELECT id as product_id, price as product_price FROM products
    WHERE name = 'Samsung Galaxy S24 Ultra'
)

-- Use the saved details to create order details
INSERT INTO order_details (order_id, product_id, quantity, price)
SELECT
    (SELECT id FROM new_order) AS order_id,
    product_id,
    2 AS quantity,
    product_price * 2
FROM
    selected_product;

COMMIT;
```

Here we register a new customer “Jack Sparrow” and place an order for him with 2 mobile phones “Samsung Galaxy S24 Ultra”.

Here **customer** , **order** and **order\_details** are all saved into database, or none of them is saved. This ensures **atomicity** when all data modifications are saved to the database as a whole.

Of course, in a production system you should check if there is a sufficient quantity of products in the **storage** tables before creating an order. If not — you can REVERT the transaction and show a corresponding error to a user or send an email with rejected order.

### Summary

Transactions ensure that your database operations are executed safely, following the **ACID principles** : Atomicity, Consistency, Isolation and Durability. Within a transaction, you can perform various operations such as selecting, inserting, updating, or deleting records across multiple tables.

Transaction ensures that all operations within a transaction are completed successfully; if at least one operation failed — the transaction is aborted.

Transaction supports 2 states:

- **COMMIT**  — ensures that all changes made to the database are saved.
- **ROLLBACK**  — ensures that all changes made to the database are not saved.

Hope you find this blog post useful. Happy coding!

_Originally published at_ [_https://antondevtips.com_](https://antondevtips.com/blog/get-started-with-sql-transactions-in-postgresql)_._

### After reading the post consider the following:

- [Subscribe](https://antondevtips.com/blog/get-started-with-sql-transactions-in-postgresql#subscribe) **to receive newsletters with the latest blog posts**
- [Download](https://github.com/AntonMartyniuk-DevTips/dev-tips-code/tree/main/backend/Databases/transactions) **the source code for this post from my** [github](https://github.com/AntonMartyniuk-DevTips/dev-tips-code/tree/main/backend/Databases/transactions) (available for my sponsors on BuyMeACoffee and Patreon)

If you like my content —  **consider supporting me**

Unlock exclusive access to the source code from the blog posts by joining my **Patreon** and **Buy Me A Coffee** communities!

[![](https://cdn-images-1.medium.com/max/233/1*GSZFx05RDUWr5pn_E9bK8w.png)](https://www.buymeacoffee.com/antonmartyniuk)

[![](https://cdn-images-1.medium.com/max/229/1*8tJk9eYCJrkzoAJw2cILSA.png)](https://www.patreon.com/bePatron?u=73769486)