MySQL¶
MySQL is one of the most popular open-source relational database management systems, widely used for web applications.
Installation¶
Using Docker¶
docker run -d \
--name mysql \
-p 3306:3306 \
-e MYSQL_ROOT_PASSWORD=rootpassword \
-e MYSQL_DATABASE=mydatabase \
-e MYSQL_USER=admin \
-e MYSQL_PASSWORD=password \
mysql:latest
Local Installation¶
Connection¶
Using mysql2 (Node.js)¶
const mysql = require('mysql2/promise');
const connection = await mysql.createConnection({
host: 'localhost',
user: 'admin',
password: 'password',
database: 'mydatabase'
});
// Query
const [rows] = await connection.execute('SELECT * FROM users');
console.log(rows);
Connection Pool¶
const pool = mysql.createPool({
host: 'localhost',
user: 'admin',
password: 'password',
database: 'mydatabase',
waitForConnections: true,
connectionLimit: 10,
queueLimit: 0
});
const [rows] = await pool.execute('SELECT * FROM users');
CRUD Operations¶
Create Table¶
CREATE TABLE users (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(100) NOT NULL,
email VARCHAR(255) UNIQUE NOT NULL,
age INT CHECK (age >= 0),
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
Insert Data¶
-- Insert single row
INSERT INTO users (name, email, age)
VALUES ('John Doe', 'john@example.com', 30);
-- Insert multiple rows
INSERT INTO users (name, email, age)
VALUES
('Jane Doe', 'jane@example.com', 25),
('Bob Smith', 'bob@example.com', 35);
-- Insert and get ID
INSERT INTO users (name, email, age)
VALUES ('Alice', 'alice@example.com', 28);
SELECT LAST_INSERT_ID();
Select Data¶
-- Select all
SELECT * FROM users;
-- Select specific columns
SELECT name, email FROM users;
-- Where clause
SELECT * FROM users WHERE age > 25;
-- Order by
SELECT * FROM users ORDER BY age DESC;
-- Limit and offset
SELECT * FROM users LIMIT 10 OFFSET 20;
-- Aggregate functions
SELECT COUNT(*), AVG(age), MAX(age) FROM users;
Update Data¶
-- Update single row
UPDATE users
SET age = 31
WHERE email = 'john@example.com';
-- Update multiple rows
UPDATE users
SET age = age + 1
WHERE age < 30;
Delete Data¶
-- Delete specific rows
DELETE FROM users WHERE age < 18;
-- Delete all rows
DELETE FROM users;
-- Truncate (faster, resets auto-increment)
TRUNCATE TABLE users;
Advanced Queries¶
Joins¶
-- Inner join
SELECT u.name, o.amount
FROM users u
INNER JOIN orders o ON u.id = o.user_id;
-- Left join
SELECT u.name, o.amount
FROM users u
LEFT JOIN orders o ON u.id = o.user_id;
-- Right join
SELECT u.name, o.amount
FROM users u
RIGHT JOIN orders o ON u.id = o.user_id;
Subqueries¶
-- Subquery in WHERE
SELECT * FROM users
WHERE id IN (SELECT user_id FROM orders WHERE amount > 100);
-- Subquery in FROM
SELECT avg_age FROM (
SELECT AVG(age) as avg_age FROM users
) AS subquery;
Group By¶
SELECT country, COUNT(*) as user_count, AVG(age) as avg_age
FROM users
GROUP BY country
HAVING COUNT(*) > 10
ORDER BY user_count DESC;
JSON Support (MySQL 5.7+)¶
-- Create table with JSON column
CREATE TABLE products (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(100),
attributes JSON
);
-- Insert JSON data
INSERT INTO products (name, attributes)
VALUES ('Laptop', '{"brand": "Dell", "specs": {"ram": "16GB", "cpu": "i7"}}');
-- Query JSON data
SELECT * FROM products
WHERE JSON_EXTRACT(attributes, '$.brand') = 'Dell';
-- Shorter syntax
SELECT * FROM products
WHERE attributes->>'$.brand' = 'Dell';
-- Update JSON field
UPDATE products
SET attributes = JSON_SET(attributes, '$.specs.ram', '32GB')
WHERE id = 1;
Indexes¶
-- Create index
CREATE INDEX idx_users_email ON users(email);
-- Unique index
CREATE UNIQUE INDEX idx_users_email ON users(email);
-- Composite index
CREATE INDEX idx_users_name_age ON users(name, age);
-- Full-text search index
CREATE FULLTEXT INDEX idx_users_name ON users(name);
-- Show indexes
SHOW INDEX FROM users;
-- Drop index
DROP INDEX idx_users_email ON users;
Transactions¶
START TRANSACTION;
INSERT INTO users (name, email) VALUES ('John', 'john@example.com');
UPDATE accounts SET balance = balance - 100 WHERE user_id = 1;
UPDATE accounts SET balance = balance + 100 WHERE user_id = 2;
COMMIT;
-- or ROLLBACK; if something goes wrong
Using mysql2 in Node.js¶
const connection = await pool.getConnection();
try {
await connection.beginTransaction();
await connection.execute('INSERT INTO users (name, email) VALUES (?, ?)', ['John', 'john@example.com']);
await connection.execute('UPDATE accounts SET balance = balance - ? WHERE user_id = ?', [100, 1]);
await connection.execute('UPDATE accounts SET balance = balance + ? WHERE user_id = ?', [100, 2]);
await connection.commit();
} catch (error) {
await connection.rollback();
throw error;
} finally {
connection.release();
}
Parameterized Queries¶
❌ Bad (SQL Injection vulnerable):
✅ Good:
const email = req.body.email;
const [rows] = await pool.execute('SELECT * FROM users WHERE email = ?', [email]);
Common Patterns¶
Pagination¶
const page = 1;
const limit = 10;
const offset = (page - 1) * limit;
const [rows] = await pool.execute(
'SELECT * FROM users ORDER BY id LIMIT ? OFFSET ?',
[limit, offset]
);
Search¶
const searchTerm = 'john';
const [rows] = await pool.execute(
'SELECT * FROM users WHERE name LIKE ?',
[`%${searchTerm}%`]
);
Bulk Insert¶
const users = [
['John', 'john@example.com'],
['Jane', 'jane@example.com'],
['Bob', 'bob@example.com']
];
const [result] = await pool.query(
'INSERT INTO users (name, email) VALUES ?',
[users]
);
Database Schema Best Practices¶
Foreign Keys¶
CREATE TABLE orders (
id INT AUTO_INCREMENT PRIMARY KEY,
user_id INT NOT NULL,
amount DECIMAL(10, 2) CHECK (amount > 0),
status ENUM('pending', 'completed', 'cancelled') DEFAULT 'pending',
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE
);
Enum Types¶
CREATE TABLE users (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(100),
role ENUM('user', 'admin', 'moderator') DEFAULT 'user'
);
Performance Tips¶
Use EXPLAIN¶
Connection Pooling¶
const pool = mysql.createPool({
connectionLimit: 10,
host: 'localhost',
user: 'admin',
password: 'password',
database: 'mydatabase'
});
Use Prepared Statements¶
Useful Commands¶
-- Show all databases
SHOW DATABASES;
-- Use database
USE mydatabase;
-- Show all tables
SHOW TABLES;
-- Describe table
DESCRIBE users;
-- Show create table statement
SHOW CREATE TABLE users;
-- Show table status
SHOW TABLE STATUS;
-- Show processlist
SHOW PROCESSLIST;
Backup and Restore¶
Backup¶
# Backup single database
mysqldump -u admin -p mydatabase > backup.sql
# Backup all databases
mysqldump -u admin -p --all-databases > all_backup.sql
# Backup specific tables
mysqldump -u admin -p mydatabase users orders > tables_backup.sql
Restore¶
# Restore database
mysql -u admin -p mydatabase < backup.sql
# Restore all databases
mysql -u admin -p < all_backup.sql
Docker Compose¶
version: '3.8'
services:
mysql:
image: mysql:latest
container_name: mysql
restart: always
ports:
- "3306:3306"
environment:
MYSQL_ROOT_PASSWORD: rootpassword
MYSQL_DATABASE: mydatabase
MYSQL_USER: admin
MYSQL_PASSWORD: password
volumes:
- mysql_data:/var/lib/mysql
command: --default-authentication-plugin=mysql_native_password
volumes:
mysql_data: