Database triggers are special automated procedures in a database that are automatically executed when certain events occur on a table or view.
Imagine you have a table called Orders
, and you want to automatically log every time an order is deleted.
You can create a DELETE trigger on the Orders
table that inserts a message into a Log
table whenever a row is deleted.
Type | Description |
---|---|
BEFORE | Executes before the triggering action |
AFTER | Executes after the triggering action |
INSTEAD OF | (for views) replaces the triggering action |
CREATE TRIGGER log_delete
AFTER DELETE ON Orders
FOR EACH ROW
BEGIN
INSERT INTO Log (action, timestamp)
VALUES ('Order deleted', NOW());
END;
Data validation
Audit logging
Enforcing business rules
Extending referential integrity
Can be hard to debug
Might trigger other actions unexpectedly
Can impact performance if overly complex
Docker Compose is a tool that lets you define and run multi-container Docker applications using a single configuration file. Instead of starting each container manually via the Docker CLI, you can describe all your services (like a web app, database, cache, etc.) in a docker-compose.yml
file and run everything with a single command.
Docker Compose = Project config + Multiple containers + One command to run it all
docker-compose.yml
version: '3.9'
services:
web:
build: .
ports:
- "5000:5000"
volumes:
- .:/code
redis:
image: "redis:alpine"
This file:
Builds and runs a local web app container
Starts a Redis container from the official image
Automatically networks the two containers
docker-compose up # Start all services in the foreground
docker-compose up -d # Start in detached (background) mode
docker-compose down # Stop and remove containers, networks, etc.
✅ Easy setup for multi-service applications
✅ Version-controlled config (great for Git)
✅ Reproducible development environments
✅ Simple startup/shutdown of entire stacks
Local development with multiple services (e.g., web app + DB)
Integration testing with full stack
Simple deployment workflows (e.g., via CI/CD)
A Prepared Statement is a programming technique, especially used when working with databases, to make SQL queries more secure and efficient.
It consists of two steps:
Prepare the SQL query with placeholders
Example in SQL:
SELECT * FROM users WHERE username = ? AND password = ?
(Some languages use :username
or other types of placeholders.)
Bind parameters and execute
The real values are bound later, for example:
$stmt->bind_param("ss", $username, $password);
$stmt->execute();
✅ Protection against SQL injection:
User input is treated separately and safely, not directly inserted into the SQL string.
✅ Faster with repeated use:
The SQL query is parsed once by the database server and can be executed multiple times efficiently (e.g., in loops).
$conn = new mysqli("localhost", "user", "pass", "database");
$stmt = $conn->prepare("SELECT * FROM users WHERE email = ?");
$stmt->bind_param("s", $email); // "s" stands for string
$email = "example@example.com";
$stmt->execute();
$result = $stmt->get_result();
A Prepared Statement separates SQL logic from user input, making it a secure (SQL Injection) and recommended practice when dealing with databases.
An Outer Join is a type of database join (commonly used in SQL) that returns records from one or both tables even if there’s no matching record in the other table.
LEFT OUTER JOIN (or simply: LEFT JOIN):
→ Returns all records from the left table, and the matching ones from the right table.
→ If there’s no match, the result is filled with NULL
values from the right table.
RIGHT OUTER JOIN (or: RIGHT JOIN):
→ Returns all records from the right table, and the matching ones from the left table.
→ If there’s no match, NULL
is used for the left side.
FULL OUTER JOIN:
→ Returns all records from both tables, with NULL
where no match exists on either side.
Suppose you have two tables:
Customers
CustomerID | Name |
1 | Anna |
2 | Bernd |
3 | Clara |
Orders
OrderID | CustomerID | Product |
101 | 2 | Book |
102 | 4 | Lamp |
CustomerID | Name | OrderID | Product |
---|---|---|---|
1 | Anna | NULL | NULL |
2 | Bernd | 101 | Book |
3 | Clara | NULL | NULL |
PDO stands for PHP Data Objects and it's a database abstraction layer in PHP. It provides an object-oriented interface to access different types of databases—such as MySQL, PostgreSQL, or SQLite—without needing to change much of your code.
✅ Consistent API
Same code style regardless of which database you use.
✅ Prepared Statements
Helps prevent SQL injection via bound parameters:
$stmt = $pdo->prepare("SELECT * FROM users WHERE id = :id");
$stmt->execute(['id' => $userId]);
✅ Transactions Support
Great for use cases like banking systems or other operations that need rollback/commit.
✅ Exception-based Error Handling
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
✅ Easy Database Switching
Switching from MySQL to PostgreSQL? Usually only the DSN and driver need to be changed.
$dsn = 'mysql:host=localhost;dbname=testdb;charset=utf8mb4';
$user = 'root';
$pass = '';
try {
$pdo = new PDO($dsn, $user, $pass);
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
echo "Connected successfully!";
} catch (PDOException $e) {
echo "Connection failed: " . $e->getMessage();
}
PDO is the recommended way to work with databases in modern PHP applications—especially for its security, flexibility, and ease of use.
Transaction Control Language (TCL) is a subset of SQL used to manage transactions in a database. A transaction is a logical unit of work that may consist of one or more SQL statements—typically INSERT
, UPDATE
, or DELETE
—that should be executed together.
TCL provides commands to ensure that transactions are properly completed or rolled back in case of errors.
Command | Description |
---|---|
COMMIT |
Saves all changes made in the current transaction permanently to the database. |
ROLLBACK |
Undoes all changes made since the last COMMIT . |
SAVEPOINT |
Creates a named point within a transaction that you can roll back to later. |
ROLLBACK TO SAVEPOINT |
Reverts changes back to a specific savepoint. |
SET TRANSACTION |
Defines characteristics for the current transaction (e.g., isolation level). |
BEGIN;
UPDATE account SET balance = balance - 100 WHERE account_id = 1;
UPDATE account SET balance = balance + 100 WHERE account_id = 2;
COMMIT;
→ Both updates are completed together. If an error occurs, you could use ROLLBACK
to cancel both operations.
TCL commands only work in database systems that support transactions (e.g., PostgreSQL, Oracle, or MySQL with InnoDB).
Data Control Language (DCL) is a subset of SQL that focuses on managing access rights and permissions within a database. DCL commands are used to control who can do what in the database.
Command | Description |
---|---|
GRANT |
Gives a user specific privileges (e.g., to read or modify data) |
REVOKE |
Removes previously granted privileges from a user |
GRANT SELECT, INSERT ON Customers TO User123;
REVOKE INSERT ON Customers FROM User123;
SELECT
– Read data
INSERT
– Add new data
UPDATE
– Modify existing data
DELETE
– Remove data
ALL
– Grant all available privileges
DCL handles security and access control in the database.
Typically used by a database administrator (DBA).
Permissions can be granted at the table, column, or database level.
DCL operations are often transaction-dependent, requiring a COMMIT
to take effect.
DDL (Data Definition Language) – Defines the database structure (e.g., tables)
DML (Data Manipulation Language) – Works with the data itself (e.g., insert or update)
TCL (Transaction Control Language) – Manages transactions (COMMIT
, ROLLBACK
)
DCL (Data Control Language) – Manages permissions and user access
DQL stands for Data Query Language, and it's a subset of SQL (Structured Query Language). It is used specifically to query data from a database without modifying it.
Read-only: DQL is used to retrieve data, not to insert, update, or delete it.
The primary command used is:
SELECT
Example:
SELECT name, birthdate FROM customers WHERE city = 'Berlin';
This command retrieves the names and birthdates of all customers living in Berlin — without changing any data.
Sub-language | Meaning | Main Purpose |
---|---|---|
DQL | Data Query Language | Reading data |
DML | Data Manipulation Language | Inserting, updating, deleting data (INSERT , UPDATE , DELETE ) |
DDL | Data Definition Language | Defining database structure (CREATE , ALTER , DROP ) |
DCL | Data Control Language | Managing access rights (GRANT , REVOKE ) |
TCL | Transaction Control Language | Handling transactions (COMMIT , ROLLBACK ) |
An Entity Manager is a core component of ORM (Object-Relational Mapping) frameworks, especially in Java (JPA – Java Persistence API), but also in other languages like PHP (Doctrine ORM).
Persisting:
Finding/Loading:
Retrieves an object by its ID or other criteria.
Example: $entityManager->find(User::class, 1);
Updating:
Tracks changes to objects and writes them to the database (usually via flush()
).
Removing:
Deletes an object from the database.
Example: $entityManager->remove($user);
Managing Transactions:
Begins, commits, or rolls back transactions.
Handling Queries:
Executes custom queries, often using DQL (Doctrine Query Language) or JPQL.
The Entity Manager tracks the state of entities:
managed (being tracked),
detached (no longer tracked),
removed (marked for deletion),
new (not yet persisted).
$user = new User();
$user->setName('Max Mustermann');
$entityManager->persist($user); // Mark for saving
$entityManager->flush(); // Write to DB
The Entity Manager is the central component for working with database objects — creating, reading, updating, deleting. It abstracts SQL and provides a clean, object-oriented way to interact with your data layer.
Doctrine DBAL (Database Abstraction Layer) is a PHP library that provides an abstraction layer for database access. It is part of the Doctrine project (a popular ORM for PHP), but it can be used independently of the ORM.
Doctrine DBAL offers a unified API to interact with different databases (such as MySQL, PostgreSQL, SQLite, etc.) without writing raw SQL specific to each database system.
Easily configure and manage connections to various database systems.
Supports connection pooling, transactions, and more.
Build SQL queries programmatically using an object-oriented API:
$qb = $conn->createQueryBuilder();
$qb->select('u.id', 'u.name')
->from('users', 'u')
->where('u.age > :age')
->setParameter('age', 18);
$stmt = $qb->executeQuery();
Database Independence
The same code works with different database systems (e.g., MySQL, PostgreSQL) with minimal changes.
Schema Management
Tools to create, update, and compare database schemas.
Useful for migrations and automation.
Data Type Conversion
Automatically converts data between PHP types and database-native types.
use Doctrine\DBAL\DriverManager;
$conn = DriverManager::getConnection([
'dbname' => 'test',
'user' => 'root',
'password' => '',
'host' => 'localhost',
'driver' => 'pdo_mysql',
]);
$result = $conn->fetchAllAssociative('SELECT * FROM users');
You might choose DBAL without ORM if:
You want full control over your SQL.
Your project doesn't need complex object-relational mapping.
You're working with a legacy database or custom queries.
Doctrine DBAL is a powerful tool for clean, portable, and secure database access in PHP. It sits between raw PDO usage and a full-featured ORM like Doctrine ORM, making it ideal for developers who want abstraction and flexibility without the overhead of ORM logic.