Sau khi nắm vững làm việc với file, bước tiếp theo là học cách kết nối MySQL trong PHP để làm việc với database. MySQL là hệ quản trị cơ sở dữ liệu phổ biến nhất cho PHP – từ website cá nhân đến hệ thống doanh nghiệp lớn. Bạn sẽ học cách kết nối, thực hiện truy vấn SELECT, INSERT, UPDATE, DELETE và bảo mật ứng dụng với Prepared Statements.
1. MySQL là gì?
MySQL là hệ quản trị cơ sở dữ liệu quan hệ (RDBMS) miễn phí, lưu trữ dữ liệu dạng bảng (tables) với hàng (rows) và cột (columns).
Tại sao dùng MySQL thay vì File?
- ✅ Hiệu suất: Truy vấn nhanh với hàng triệu bản ghi
- ✅ Bảo mật: Phân quyền người dùng, mã hóa dữ liệu
- ✅ Quan hệ: Liên kết bảng (foreign key), JOIN
- ✅ Đồng thời: Nhiều người dùng cùng lúc
- ✅ Backup: Sao lưu, phục hồi dễ dàng
- ✅ Tìm kiếm: WHERE, LIKE, ORDER BY, LIMIT…
2. Cài đặt MySQL
2.1. XAMPP (Windows/Mac/Linux)
# XAMPP đã bao gồm MySQL
# Mở XAMPP Control Panel → Start Apache + MySQL
# Truy cập phpMyAdmin:
http://localhost/phpmyadmin
# Thông tin kết nối mặc định:
Host: localhost
Username: root
Password: (để trống)
Port: 3306
2.2. Tạo Database và Table
-- Tạo database
CREATE DATABASE test_db;
-- Sử dụng database
USE test_db;
-- Tạo bảng users
CREATE TABLE users (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(100) NOT NULL,
email VARCHAR(100) UNIQUE NOT NULL,
password VARCHAR(255) NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
-- Insert dữ liệu mẫu
INSERT INTO users (name, email, password) VALUES
('Nguyễn Văn A', 'a@email.com', 'password123'),
('Trần Thị B', 'b@email.com', 'password456');
3. Hai cách kết nối: MySQLi vs PDO
| Tiêu chí | MySQLi | PDO |
|---|---|---|
| Database | Chỉ MySQL | 12+ databases |
| OOP/Procedural | ✅ Cả hai | Chỉ OOP |
| Prepared Statements | ✅ Có | ✅ Có |
| Named Parameters | ❌ Không | ✅ Có |
| Khuyến nghị | Dự án nhỏ/vừa | Dự án lớn/đa DB |
💡 Khuyến nghị: Dùng PDO cho dự án mới vì linh hoạt hơn và hỗ trợ nhiều database.
4. Kết nối với MySQLi
4.1. Kết nối OOP (khuyến nghị)
<?php
// Thông tin kết nối
$host = "localhost";
$username = "root";
$password = "";
$database = "test_db";
// Tạo kết nối
$conn = new mysqli($host, $username, $password, $database);
// Kiểm tra kết nối
if ($conn->connect_error) {
die("Kết nối thất bại: " . $conn->connect_error);
}
echo "Kết nối thành công!";
// Đóng kết nối
$conn->close();
?>4.2. Kết nối Procedural
<?php
$conn = mysqli_connect("localhost", "root", "", "test_db");
if (!$conn) {
die("Kết nối thất bại: " . mysqli_connect_error());
}
echo "Kết nối thành công!";
mysqli_close($conn);
?>4.3. File cấu hình kết nối
<?php
// config.php
define('DB_HOST', 'localhost');
define('DB_USER', 'root');
define('DB_PASS', '');
define('DB_NAME', 'test_db');
$conn = new mysqli(DB_HOST, DB_USER, DB_PASS, DB_NAME);
if ($conn->connect_error) {
die("Kết nối thất bại: " . $conn->connect_error);
}
// Đặt charset UTF-8 (quan trọng cho tiếng Việt)
$conn->set_charset("utf8mb4");
?>5. Kết nối với PDO
<?php
$host = "localhost";
$dbname = "test_db";
$username = "root";
$password = "";
try {
// Tạo kết nối PDO
$pdo = new PDO(
"mysql:host=$host;dbname=$dbname;charset=utf8mb4",
$username,
$password
);
// Đặt chế độ lỗi
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
// Đặt fetch mode mặc định
$pdo->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC);
echo "Kết nối PDO thành công!";
} catch (PDOException $e) {
die("Kết nối thất bại: " . $e->getMessage());
}
?>6. Truy vấn SELECT – Đọc dữ liệu
6.1. SELECT với MySQLi
<?php
require 'config.php';
// Truy vấn SQL
$sql = "SELECT * FROM users";
$result = $conn->query($sql);
// Kiểm tra có dữ liệu không
if ($result->num_rows > 0) {
// Duyệt từng dòng
while ($row = $result->fetch_assoc()) {
echo "ID: " . $row['id'] . "<br>";
echo "Tên: " . $row['name'] . "<br>";
echo "Email: " . $row['email'] . "<br><hr>";
}
} else {
echo "Không có dữ liệu";
}
$conn->close();
?>6.2. SELECT với PDO
<?php
require 'config.php';
$sql = "SELECT * FROM users";
$stmt = $pdo->query($sql);
// Fetch tất cả
$users = $stmt->fetchAll();
foreach ($users as $user) {
echo "Tên: " . $user['name'] . "<br>";
echo "Email: " . $user['email'] . "<br><hr>";
}
// Hoặc fetch từng dòng
$stmt = $pdo->query($sql);
while ($user = $stmt->fetch()) {
echo $user['name'] . "<br>";
}
?>6.3. SELECT với điều kiện WHERE
<?php
// MySQLi
$sql = "SELECT * FROM users WHERE id = 1";
$result = $conn->query($sql);
$user = $result->fetch_assoc();
echo "Tên: " . $user['name'];
// PDO
$sql = "SELECT * FROM users WHERE id = 1";
$stmt = $pdo->query($sql);
$user = $stmt->fetch();
echo "Email: " . $user['email'];
?>7. INSERT – Thêm dữ liệu
7.1. INSERT với MySQLi
<?php
require 'config.php';
$name = "Lê Văn C";
$email = "c@email.com";
$password = password_hash("password789", PASSWORD_DEFAULT);
$sql = "INSERT INTO users (name, email, password)
VALUES ('$name', '$email', '$password')";
if ($conn->query($sql) === TRUE) {
echo "Thêm thành công! ID mới: " . $conn->insert_id;
} else {
echo "Lỗi: " . $conn->error;
}
$conn->close();
?>7.2. INSERT với PDO
<?php
$name = "Phạm Thị D";
$email = "d@email.com";
$password = password_hash("password000", PASSWORD_DEFAULT);
$sql = "INSERT INTO users (name, email, password)
VALUES ('$name', '$email', '$password')";
try {
$pdo->exec($sql);
echo "Thêm thành công! ID mới: " . $pdo->lastInsertId();
} catch (PDOException $e) {
echo "Lỗi: " . $e->getMessage();
}
?>⚠️ CẢNH BÁO: Code trên có lỗ hổng SQL Injection! Xem phần Prepared Statements bên dưới.
8. UPDATE – Cập nhật dữ liệu
<?php
// MySQLi
$sql = "UPDATE users SET name = 'Nguyễn Văn An' WHERE id = 1";
if ($conn->query($sql) === TRUE) {
echo "Cập nhật thành công! Số dòng: " . $conn->affected_rows;
} else {
echo "Lỗi: " . $conn->error;
}
// PDO
$sql = "UPDATE users SET email = 'newemail@email.com' WHERE id = 2";
try {
$affected = $pdo->exec($sql);
echo "Cập nhật $affected dòng";
} catch (PDOException $e) {
echo "Lỗi: " . $e->getMessage();
}
?>9. DELETE – Xóa dữ liệu
<?php
// MySQLi
$sql = "DELETE FROM users WHERE id = 3";
if ($conn->query($sql) === TRUE) {
echo "Xóa thành công! Số dòng: " . $conn->affected_rows;
} else {
echo "Lỗi: " . $conn->error;
}
// PDO
$sql = "DELETE FROM users WHERE id = 4";
try {
$affected = $pdo->exec($sql);
echo "Đã xóa $affected dòng";
} catch (PDOException $e) {
echo "Lỗi: " . $e->getMessage();
}
?>10. Prepared Statements – Bảo mật SQL Injection
SQL Injection là lỗ hổng bảo mật nghiêm trọng nhất trong web:
<?php
// ❌ NGUY HIỂM - SQL Injection
$id = $_GET['id']; // Hacker nhập: 1 OR 1=1
$sql = "SELECT * FROM users WHERE id = $id";
// → SELECT * FROM users WHERE id = 1 OR 1=1 (lấy toàn bộ!)
// ❌ NGUY HIỂM
$email = $_POST['email']; // Hacker nhập: ' OR '1'='1
$password = $_POST['password'];
$sql = "SELECT * FROM users WHERE email = '$email' AND password = '$password'";
// → Đăng nhập mà không cần mật khẩu!
?>10.1. Prepared Statements với MySQLi
<?php
// SELECT
$id = $_GET['id'];
$stmt = $conn->prepare("SELECT * FROM users WHERE id = ?");
$stmt->bind_param("i", $id); // i = integer, s = string
$stmt->execute();
$result = $stmt->get_result();
$user = $result->fetch_assoc();
echo "Tên: " . $user['name'];
$stmt->close();
// INSERT
$name = $_POST['name'];
$email = $_POST['email'];
$password = password_hash($_POST['password'], PASSWORD_DEFAULT);
$stmt = $conn->prepare("INSERT INTO users (name, email, password) VALUES (?, ?, ?)");
$stmt->bind_param("sss", $name, $email, $password); // s = string
if ($stmt->execute()) {
echo "Thêm thành công!";
} else {
echo "Lỗi: " . $stmt->error;
}
$stmt->close();
// UPDATE
$new_name = $_POST['name'];
$id = $_POST['id'];
$stmt = $conn->prepare("UPDATE users SET name = ? WHERE id = ?");
$stmt->bind_param("si", $new_name, $id);
$stmt->execute();
echo "Cập nhật " . $stmt->affected_rows . " dòng";
$stmt->close();
?>Các loại bind_param:
i– Integer (số nguyên)d– Double (số thực)s– String (chuỗi)b– Blob (dữ liệu nhị phân)
10.2. Prepared Statements với PDO
<?php
// Cách 1: Positional parameters (?)
$id = $_GET['id'];
$stmt = $pdo->prepare("SELECT * FROM users WHERE id = ?");
$stmt->execute([$id]);
$user = $stmt->fetch();
echo "Email: " . $user['email'];
// Cách 2: Named parameters (:name) - Khuyến nghị
$email = $_POST['email'];
$password = $_POST['password'];
$stmt = $pdo->prepare("SELECT * FROM users WHERE email = :email AND password = :password");
$stmt->execute([
':email' => $email,
':password' => $password
]);
$user = $stmt->fetch();
if ($user) {
echo "Đăng nhập thành công";
} else {
echo "Sai email hoặc mật khẩu";
}
// INSERT
$stmt = $pdo->prepare("INSERT INTO users (name, email, password) VALUES (:name, :email, :password)");
$stmt->execute([
':name' => $_POST['name'],
':email' => $_POST['email'],
':password' => password_hash($_POST['password'], PASSWORD_DEFAULT)
]);
echo "Thêm thành công! ID: " . $pdo->lastInsertId();
// UPDATE
$stmt = $pdo->prepare("UPDATE users SET name = :name WHERE id = :id");
$stmt->execute([
':name' => $_POST['name'],
':id' => $_POST['id']
]);
echo "Cập nhật " . $stmt->rowCount() . " dòng";
?>11. Ví dụ hoàn chỉnh: CRUD với PDO
11.1. Database.php – Class kết nối
<?php
class Database {
private $host = "localhost";
private $dbname = "test_db";
private $username = "root";
private $password = "";
private $conn;
public function connect() {
$this->conn = null;
try {
$this->conn = new PDO(
"mysql:host=$this->host;dbname=$this->dbname;charset=utf8mb4",
$this->username,
$this->password
);
$this->conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$this->conn->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC);
} catch (PDOException $e) {
echo "Lỗi kết nối: " . $e->getMessage();
}
return $this->conn;
}
}
?>11.2. User.php – Class CRUD
<?php
require_once 'Database.php';
class User {
private $conn;
private $table = "users";
public function __construct() {
$db = new Database();
$this->conn = $db->connect();
}
// Lấy tất cả users
public function getAll() {
$sql = "SELECT id, name, email, created_at FROM $this->table ORDER BY id DESC";
$stmt = $this->conn->query($sql);
return $stmt->fetchAll();
}
// Lấy 1 user theo ID
public function getById($id) {
$stmt = $this->conn->prepare("SELECT * FROM $this->table WHERE id = ?");
$stmt->execute([$id]);
return $stmt->fetch();
}
// Thêm user
public function create($name, $email, $password) {
$stmt = $this->conn->prepare(
"INSERT INTO $this->table (name, email, password) VALUES (:name, :email, :password)"
);
return $stmt->execute([
':name' => $name,
':email' => $email,
':password' => password_hash($password, PASSWORD_DEFAULT)
]);
}
// Cập nhật user
public function update($id, $name, $email) {
$stmt = $this->conn->prepare(
"UPDATE $this->table SET name = :name, email = :email WHERE id = :id"
);
return $stmt->execute([
':name' => $name,
':email' => $email,
':id' => $id
]);
}
// Xóa user
public function delete($id) {
$stmt = $this->conn->prepare("DELETE FROM $this->table WHERE id = ?");
return $stmt->execute([$id]);
}
// Đăng nhập
public function login($email, $password) {
$stmt = $this->conn->prepare("SELECT * FROM $this->table WHERE email = ?");
$stmt->execute([$email]);
$user = $stmt->fetch();
if ($user && password_verify($password, $user['password'])) {
return $user;
}
return false;
}
}
?>11.3. index.php – Sử dụng
<?php
require_once 'User.php';
$userObj = new User();
// Lấy danh sách users
$users = $userObj->getAll();
echo "<h2>Danh sách Users</h2>";
echo "<table border='1'>";
echo "<tr><th>ID</th><th>Tên</th><th>Email</th><th>Ngày tạo</th></tr>";
foreach ($users as $user) {
echo "<tr>";
echo "<td>" . $user['id'] . "</td>";
echo "<td>" . htmlspecialchars($user['name']) . "</td>";
echo "<td>" . htmlspecialchars($user['email']) . "</td>";
echo "<td>" . $user['created_at'] . "</td>";
echo "</tr>";
}
echo "</table>";
// Thêm user mới
if ($_SERVER['REQUEST_METHOD'] == 'POST' && isset($_POST['add'])) {
$userObj->create($_POST['name'], $_POST['email'], $_POST['password']);
header("Location: index.php");
exit;
}
// Xóa user
if (isset($_GET['delete'])) {
$userObj->delete($_GET['delete']);
header("Location: index.php");
exit;
}
?>
<h3>Thêm User</h3>
<form method="POST">
<input type="text" name="name" placeholder="Tên" required><br>
<input type="email" name="email" placeholder="Email" required><br>
<input type="password" name="password" placeholder="Mật khẩu" required><br>
<button type="submit" name="add">Thêm</button>
</form>12. Xử lý lỗi và Transaction
12.1. Try-Catch với PDO
<?php
try {
$pdo->beginTransaction();
// Truy vấn 1
$pdo->exec("INSERT INTO users (name, email, password) VALUES ('User 1', 'user1@test.com', 'pass')");
// Truy vấn 2
$pdo->exec("INSERT INTO orders (user_id, total) VALUES (1, 1000000)");
// Commit nếu thành công
$pdo->commit();
echo "Transaction thành công";
} catch (PDOException $e) {
// Rollback nếu có lỗi
$pdo->rollBack();
echo "Lỗi: " . $e->getMessage();
}
?>Tóm tắt
Qua bài này bạn đã nắm được:
- ✅ MySQL: Hệ quản trị CSDL quan hệ, lưu trữ dữ liệu dạng bảng
- ✅ MySQLi: Extension chỉ cho MySQL, có OOP và Procedural
- ✅ PDO: Hỗ trợ 12+ databases, chỉ OOP, linh hoạt hơn (khuyến nghị)
- ✅ Kết nối:
new mysqli()hoặcnew PDO() - ✅ SELECT:
query()hoặcprepare() + execute() + fetch() - ✅ INSERT:
INSERT INTO table VALUES (...) - ✅ UPDATE:
UPDATE table SET ... WHERE ... - ✅ DELETE:
DELETE FROM table WHERE ... - ✅ Prepared Statements: Bảo vệ khỏi SQL Injection – BẮT BUỘC dùng!
- ✅ Transaction:
beginTransaction() + commit()/rollBack()
Bài tiếp theo, bạn sẽ học về Mini Project CRUD xây dựng ứng dụng quản lý hoàn chỉnh.
🎯 Bài tập thực hành
- Bài 1: Tạo database
libraryvới bảngbooks(id, title, author, year, created_at). Viết code hiển thị danh sách sách, thêm sách mới. - Bài 2: Tạo form đăng ký/đăng nhập. Lưu user vào database với mật khẩu đã hash. Kiểm tra email trùng khi đăng ký.
- Bài 3: Tạo class
Productvới CRUD đầy đủ (getAll, getById, create, update, delete). Sử dụng PDO và Prepared Statements.
Gợi ý Bài 1:
<?php
// Kết nối
$pdo = new PDO("mysql:host=localhost;dbname=library;charset=utf8mb4", "root", "");
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
// Thêm sách
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
$stmt = $pdo->prepare("INSERT INTO books (title, author, year) VALUES (?, ?, ?)");
$stmt->execute([$_POST['title'], $_POST['author'], $_POST['year']]);
header("Location: index.php");
exit;
}
// Hiển thị
$books = $pdo->query("SELECT * FROM books ORDER BY id DESC")->fetchAll();
?>
<h2>Danh sách sách</h2>
<table border="1">
<tr><th>ID</th><th>Tiêu đề</th><th>Tác giả</th><th>Năm</th></tr>
<?php foreach ($books as $book): ?>
<tr>
<td><?= $book['id'] ?></td>
<td><?= htmlspecialchars($book['title']) ?></td>
<td><?= htmlspecialchars($book['author']) ?></td>
<td><?= $book['year'] ?></td>
</tr>
<?php endforeach; ?>
</table>
<form method="POST">
<input type="text" name="title" placeholder="Tiêu đề" required>
<input type="text" name="author" placeholder="Tác giả" required>
<input type="number" name="year" placeholder="Năm" required>
<button type="submit">Thêm</button>
</form>Gợi ý Bài 2:
<?php
session_start();
$pdo = new PDO("mysql:host=localhost;dbname=test_db;charset=utf8mb4", "root", "");
// Đăng ký
if (isset($_POST['register'])) {
$email = $_POST['email'];
// Kiểm tra email tồn tại
$stmt = $pdo->prepare("SELECT id FROM users WHERE email = ?");
$stmt->execute([$email]);
if ($stmt->rowCount() > 0) {
echo "Email đã tồn tại!";
} else {
$stmt = $pdo->prepare("INSERT INTO users (name, email, password) VALUES (?, ?, ?)");
$stmt->execute([
$_POST['name'],
$email,
password_hash($_POST['password'], PASSWORD_DEFAULT)
]);
echo "Đăng ký thành công!";
}
}
// Đăng nhập
if (isset($_POST['login'])) {
$stmt = $pdo->prepare("SELECT * FROM users WHERE email = ?");
$stmt->execute([$_POST['email']]);
$user = $stmt->fetch();
if ($user && password_verify($_POST['password'], $user['password'])) {
$_SESSION['user_id'] = $user['id'];
echo "Đăng nhập thành công!";
} else {
echo "Sai email hoặc mật khẩu!";
}
}
?>