Bạn đang tìm hiểu cách quản lý cơ sở dữ liệu hiệu quả trong lập trình PHP? Bài viết này sẽ giúp bạn nắm vững các câu lệnh SQL DDL (CREATE, ALTER, DROP) để định nghĩa cấu trúc dữ liệu và DML (SELECT, INSERT, UPDATE, DELETE) để thao tác với dữ liệu. Kèm theo các ví dụ PHP sử dụng PDO chi tiết, bạn sẽ biết cách thực hiện các thao tác cơ bản và quan trọng nhất là phòng chống SQL Injection hiệu quả, đảm bảo ứng dụng của bạn an toàn và mạnh mẽ. Khám phá ngay để nâng cao kỹ năng lập trình PHP và quản lý database chuyên nghiệp!
Trong thế giới phát triển web hiện đại với PHP, việc tương tác với cơ sở dữ liệu là một kỹ năng không thể thiếu. SQL (Structured Query Language) là ngôn ngữ chuẩn để quản lý và truy vấn cơ sở dữ liệu, và trong SQL, chúng ta có hai nhóm câu lệnh chính đóng vai trò cốt lõi: DDL (Data Definition Language) và DML (Data Manipulation Language).
Bài viết này sẽ đi sâu vào từng nhóm câu lệnh, giải thích chức năng, cung cấp ví dụ thực tế trong lập trình PHP (sử dụng PDO - PHP Data Objects) và đưa ra các thực tiễn tốt nhất để đảm bảo ứng dụng của bạn an toàn, hiệu quả và dễ bảo trì.
DDL là tập hợp các câu lệnh SQL dùng để định nghĩa và quản lý cấu trúc của cơ sở dữ liệu và các đối tượng bên trong nó (như bảng, chỉ mục, view, trigger). Các câu lệnh DDL thường được sử dụng khi bạn thiết kế hoặc thay đổi schema của cơ sở dữ liệu.
Câu lệnh CREATE
được dùng để tạo các đối tượng mới trong cơ sở dữ liệu.
CREATE DATABASE ten_co_so_du_lieu;
PRIMARY KEY
, NOT NULL
, UNIQUE
, DEFAULT
.
CREATE TABLE users (
id INT AUTO_INCREMENT PRIMARY KEY,
username VARCHAR(50) NOT NULL UNIQUE,
email VARCHAR(100) NOT NULL,
password VARCHAR(255) NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
Cách thực thi CREATE trong PHP (sử dụng PDO):
Đầu tiên, hãy đảm bảo bạn đã thiết lập kết nối PDO.
<?php
$host = 'localhost';
$db = 'your_database_name'; // Có thể bỏ qua nếu bạn muốn tạo DB trước
$user = 'your_username';
$pass = 'your_password';
$charset = 'utf8mb4';
$dsn = "mysql:host=$host;dbname=$db;charset=$charset";
$options = [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
PDO::ATTR_EMULATE_PREPARES => false,
];
try {
$pdo = new PDO($dsn, $user, $pass, $options);
echo "Kết nối cơ sở dữ liệu thành công! <br>";
// *** Ví dụ: Tạo bảng 'users' ***
$sql_create_table = "
CREATE TABLE IF NOT EXISTS users (
id INT AUTO_INCREMENT PRIMARY KEY,
username VARCHAR(50) NOT NULL UNIQUE,
email VARCHAR(100) NOT NULL,
password VARCHAR(255) NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);";
$pdo->exec($sql_create_table);
echo "Bảng 'users' đã được tạo (nếu chưa tồn tại) hoặc đã tồn tại. <br>";
// *** Ví dụ: Tạo một bảng khác 'products' ***
$sql_create_products_table = "
CREATE TABLE IF NOT EXISTS products (
product_id INT AUTO_INCREMENT PRIMARY KEY,
product_name VARCHAR(255) NOT NULL,
price DECIMAL(10, 2) NOT NULL,
stock_quantity INT DEFAULT 0,
description TEXT
);";
$pdo->exec($sql_create_products_table);
echo "Bảng 'products' đã được tạo (nếu chưa tồn tại) hoặc đã tồn tại. <br>";
} catch (\PDOException $e) {
throw new \PDOException($e->getMessage(), (int)$e->getCode());
}
?>
Lưu ý:
IF NOT EXISTS
khi tạo bảng để tránh lỗi nếu bảng đã tồn tại.$pdo->exec()
được dùng cho các câu lệnh DDL không trả về tập hợp kết quả.Câu lệnh ALTER
được dùng để thay đổi cấu trúc của một bảng đã tồn tại. Bạn có thể thêm cột, xóa cột, thay đổi kiểu dữ liệu của cột, thêm hoặc xóa ràng buộc.
ALTER TABLE users ADD COLUMN phone_number VARCHAR(20);
ALTER TABLE products MODIFY COLUMN description VARCHAR(500);
ALTER TABLE users DROP COLUMN phone_number;
Cách thực thi ALTER trong PHP (sử dụng PDO):
<?php
// ... (Phần kết nối PDO tương tự như trên) ...
try {
$pdo = new PDO($dsn, $user, $pass, $options);
echo "Kết nối cơ sở dữ liệu thành công! <br>";
// *** Ví dụ: Thêm cột 'address' vào bảng 'users' ***
$sql_add_column = "ALTER TABLE users ADD COLUMN address VARCHAR(255) AFTER email;";
$pdo->exec($sql_add_column);
echo "Cột 'address' đã được thêm vào bảng 'users'. <br>";
// *** Ví dụ: Thay đổi kiểu dữ liệu của cột 'stock_quantity' trong bảng 'products' ***
$sql_modify_column = "ALTER TABLE products MODIFY COLUMN stock_quantity INT NOT NULL DEFAULT 0;";
$pdo->exec($sql_modify_column);
echo "Cột 'stock_quantity' trong bảng 'products' đã được sửa đổi. <br>";
} catch (\PDOException $e) {
// Xử lý lỗi. Lưu ý: ALTER sẽ báo lỗi nếu cột đã tồn tại hoặc thay đổi không hợp lệ.
echo "Lỗi khi thực hiện ALTER: " . $e->getMessage() . "<br>";
}
?>
Câu lệnh DROP
được dùng để xóa hoàn toàn các đối tượng khỏi cơ sở dữ liệu. Hãy cực kỳ cẩn thận khi sử dụng DROP
vì dữ liệu sẽ bị mất vĩnh viễn!
DROP TABLE users;
DROP DATABASE ten_co_so_du_lieu;
Cách thực thi DROP trong PHP (sử dụng PDO):
<?php
// ... (Phần kết nối PDO tương tự như trên) ...
try {
$pdo = new PDO($dsn, $user, $pass, $options);
echo "Kết nối cơ sở dữ liệu thành công! <br>";
// *** Ví dụ: Xóa bảng 'products' ***
// RẤT CẨN THẬN KHI CHẠY CÂU LỆNH NÀY TRÊN MÔI TRƯỜNG THỰC TẾ!
$sql_drop_table = "DROP TABLE IF EXISTS products;";
$pdo->exec($sql_drop_table);
echo "Bảng 'products' đã được xóa (nếu tồn tại). <br>";
// *** Ví dụ: Xóa cơ sở dữ liệu (chỉ chạy khi thật sự cần thiết) ***
// Bạn cần kết nối đến một database khác hoặc không specify database trong DSN để DROP database hiện tại
// $pdo_no_db = new PDO("mysql:host=$host;charset=$charset", $user, $pass, $options);
// $sql_drop_database = "DROP DATABASE IF EXISTS your_database_name;";
// $pdo_no_db->exec($sql_drop_database);
// echo "Cơ sở dữ liệu 'your_database_name' đã được xóa. <br>";
} catch (\PDOException $e) {
echo "Lỗi khi thực hiện DROP: " . $e->getMessage() . "<br>";
}
?>
Thực tiễn tốt nhất cho DDL trong PHP:
IF EXISTS
hoặc IF NOT EXISTS
: Để tránh lỗi khi đối tượng đã hoặc chưa tồn tại.DROP
hoặc ALTER
cho tài khoản ứng dụng PHP trong môi trường sản xuất nếu không thật sự cần thiết. Các thay đổi DDL nên được thực hiện thủ công bởi quản trị viên hoặc qua các công cụ quản lý cơ sở dữ liệu, hoặc thông qua hệ thống di chuyển (migrations) an toàn.DML là tập hợp các câu lệnh SQL dùng để thao tác với dữ liệu bên trong các bảng của cơ sở dữ liệu. Đây là những câu lệnh bạn sẽ sử dụng thường xuyên nhất trong các ứng dụng web PHP.
Câu lệnh SELECT
dùng để truy vấn và lấy dữ liệu từ một hoặc nhiều bảng. Đây là câu lệnh phổ biến nhất trong DML.
SELECT * FROM users;
SELECT username, email FROM users;
SELECT * FROM users WHERE id = 1;
SELECT * FROM products WHERE price > 100 AND stock_quantity > 0;
SELECT * FROM users ORDER BY created_at DESC;
SELECT * FROM products LIMIT 10 OFFSET 0; -- Lấy 10 sản phẩm đầu tiên
SELECT u.username, p.product_name
FROM users u
JOIN orders o ON u.id = o.user_id
JOIN products p ON o.product_id = p.product_id;
Cách thực thi SELECT trong PHP (sử dụng PDO):
<?php
// ... (Phần kết nối PDO tương tự như trên) ...
try {
$pdo = new PDO($dsn, $user, $pass, $options);
echo "Kết nối cơ sở dữ liệu thành công! <br>";
// *** Ví dụ 1: Lấy tất cả người dùng ***
$stmt = $pdo->query("SELECT id, username, email FROM users");
$users = $stmt->fetchAll(); // Lấy tất cả các hàng dưới dạng mảng
echo "<h3>Danh sách người dùng:</h3>";
if (count($users) > 0) {
foreach ($users as $user) {
echo "ID: " . $user['id'] . ", Username: " . $user['username'] . ", Email: " . $user['email'] . "<br>";
}
} else {
echo "Không có người dùng nào.";
}
echo "<hr>";
// *** Ví dụ 2: Lấy người dùng theo ID (sử dụng prepared statement) ***
$user_id = 1;
$stmt = $pdo->prepare("SELECT id, username, email FROM users WHERE id = :id");
$stmt->bindParam(':id', $user_id, PDO::PARAM_INT); // Hoặc $stmt->execute([':id' => $user_id]);
$stmt->execute();
$user_by_id = $stmt->fetch(); // Lấy một hàng
echo "<h3>Người dùng có ID = {$user_id}:</h3>";
if ($user_by_id) {
echo "ID: " . $user_by_id['id'] . ", Username: " . $user_by_id['username'] . ", Email: " . $user_by_id['email'] . "<br>";
} else {
echo "Không tìm thấy người dùng có ID = {$user_id}.";
}
echo "<hr>";
} catch (\PDOException $e) {
echo "Lỗi khi thực hiện SELECT: " . $e->getMessage() . "<br>";
}
?>
Câu lệnh INSERT
dùng để thêm một hoặc nhiều hàng dữ liệu mới vào một bảng.
INSERT INTO users (username, email, password)
VALUES ('john_doe', 'john.doe@example.com', 'hashed_password_123');
INSERT INTO products (product_name, price, stock_quantity)
VALUES ('Laptop ABC', 1200.50, 50);
Cách thực thi INSERT trong PHP (sử dụng PDO - LUÔN SỬ DỤNG PREPARED STATEMENTS!):
Prepared statements là cách an toàn nhất để thực hiện các câu lệnh DML có chứa dữ liệu từ người dùng, ngăn chặn các cuộc tấn công SQL Injection.
<?php
// ... (Phần kết nối PDO tương tự như trên) ...
try {
$pdo = new PDO($dsn, $user, $pass, $options);
echo "Kết nối cơ sở dữ liệu thành công! <br>";
// Dữ liệu mẫu để chèn
$username = 'alice_smith';
$email = 'alice.smith@example.com';
$password_hash = password_hash('secure_password_abc', PASSWORD_DEFAULT); // Luôn mã hóa mật khẩu!
// *** Ví dụ: Chèn dữ liệu vào bảng 'users' ***
$sql_insert_user = "INSERT INTO users (username, email, password) VALUES (:username, :email, :password)";
$stmt = $pdo->prepare($sql_insert_user);
// Gán giá trị cho các tham số
$stmt->bindParam(':username', $username);
$stmt->bindParam(':email', $email);
$stmt->bindParam(':password', $password_hash);
$stmt->execute();
echo "Người dùng '{$username}' đã được thêm vào thành công. <br>";
echo "ID của người dùng vừa thêm: " . $pdo->lastInsertId() . "<br>";
echo "<hr>";
// Thêm một sản phẩm
$product_name = 'Smartwatch X';
$price = 299.99;
$stock = 100;
$sql_insert_product = "INSERT INTO products (product_name, price, stock_quantity) VALUES (:name, :price, :stock)";
$stmt_product = $pdo->prepare($sql_insert_product);
$stmt_product->bindParam(':name', $product_name);
$stmt_product->bindParam(':price', $price);
$stmt_product->bindParam(':stock', $stock, PDO::PARAM_INT);
$stmt_product->execute();
echo "Sản phẩm '{$product_name}' đã được thêm vào thành công. <br>";
} catch (\PDOException $e) {
echo "Lỗi khi thực hiện INSERT: " . $e->getMessage() . "<br>";
}
?>
Câu lệnh UPDATE
dùng để sửa đổi dữ liệu của các hàng hiện có trong một bảng. Luôn sử dụng mệnh đề WHERE
để chỉ định hàng cần cập nhật, nếu không, tất cả các hàng sẽ bị ảnh hưởng!
UPDATE users
SET email = 'new.email@example.com'
WHERE id = 1;
UPDATE products
SET price = 1150.00, stock_quantity = 45
WHERE product_name = 'Laptop ABC';
Cách thực thi UPDATE trong PHP (sử dụng PDO - LUÔN SỬ DỤNG PREPARED STATEMENTS!):
<?php
// ... (Phần kết nối PDO tương tự như trên) ...
try {
$pdo = new PDO($dsn, $user, $pass, $options);
echo "Kết nối cơ sở dữ liệu thành công! <br>";
// Dữ liệu mẫu để cập nhật
$new_email = 'updated_alice@example.com';
$user_id_to_update = 2; // Giả sử ID người dùng Alice là 2
// *** Ví dụ: Cập nhật email của người dùng có ID nhất định ***
$sql_update_user = "UPDATE users SET email = :email WHERE id = :id";
$stmt = $pdo->prepare($sql_update_user);
$stmt->bindParam(':email', $new_email);
$stmt->bindParam(':id', $user_id_to_update, PDO::PARAM_INT);
$stmt->execute();
echo "Đã cập nhật email cho người dùng ID {$user_id_to_update}. Số hàng bị ảnh hưởng: " . $stmt->rowCount() . "<br>";
echo "<hr>";
// Cập nhật giá sản phẩm
$new_price = 320.00;
$product_name_to_update = 'Smartwatch X';
$sql_update_product = "UPDATE products SET price = :price WHERE product_name = :name";
$stmt_product = $pdo->prepare($sql_update_product);
$stmt_product->bindParam(':price', $new_price);
$stmt_product->bindParam(':name', $product_name_to_update);
$stmt_product->execute();
echo "Đã cập nhật giá cho sản phẩm '{$product_name_to_update}'. Số hàng bị ảnh hưởng: " . $stmt_product->rowCount() . "<br>";
} catch (\PDOException $e) {
echo "Lỗi khi thực hiện UPDATE: " . $e->getMessage() . "<br>";
}
?>
Câu lệnh DELETE
dùng để xóa một hoặc nhiều hàng dữ liệu từ một bảng. Tương tự UPDATE
, luôn sử dụng mệnh đề WHERE
để chỉ định hàng cần xóa, nếu không, tất cả các hàng trong bảng sẽ bị xóa!
DELETE FROM users
WHERE id = 3;
DELETE FROM products
WHERE stock_quantity = 0; -- Xóa tất cả sản phẩm hết hàng
Cách thực thi DELETE trong PHP (sử dụng PDO - LUÔN SỬ DỤNG PREPARED STATEMENTS!):
<?php
// ... (Phần kết nối PDO tương tự như trên) ...
try {
$pdo = new PDO($dsn, $user, $pass, $options);
echo "Kết nối cơ sở dữ liệu thành công! <br>";
// ID người dùng cần xóa
$user_id_to_delete = 3;
// *** Ví dụ: Xóa người dùng có ID nhất định ***
$sql_delete_user = "DELETE FROM users WHERE id = :id";
$stmt = $pdo->prepare($sql_delete_user);
$stmt->bindParam(':id', $user_id_to_delete, PDO::PARAM_INT);
$stmt->execute();
echo "Đã xóa người dùng ID {$user_id_to_delete}. Số hàng bị ảnh hưởng: " . $stmt->rowCount() . "<br>";
echo "<hr>";
// Xóa sản phẩm có số lượng tồn kho = 0
$stock_threshold = 0;
$sql_delete_products_out_of_stock = "DELETE FROM products WHERE stock_quantity = :stock";
$stmt_product = $pdo->prepare($sql_delete_products_out_of_stock);
$stmt_product->bindParam(':stock', $stock_threshold, PDO::PARAM_INT);
$stmt_product->execute();
echo "Đã xóa các sản phẩm hết hàng. Số hàng bị ảnh hưởng: " . $stmt_product->rowCount() . "<br>";
} catch (\PDOException $e) {
echo "Lỗi khi thực hiện DELETE: " . $e->getMessage() . "<br>";
}
?>
Thực tiễn tốt nhất cho DML trong PHP:
$pdo->prepare()
và sau đó $stmt->execute()
với các tham số (ví dụ: [':param' => $value]
) hoặc $stmt->bindParam()
.try-catch
để bắt và xử lý các ngoại lệ PDO. Điều này giúp bạn debug dễ dàng hơn và cung cấp thông báo lỗi thân thiện cho người dùng (hoặc ghi log).$pdo->beginTransaction()
, $pdo->commit()
, $pdo->rollBack()
). Điều này đảm bảo tính toàn vẹn của dữ liệu: hoặc tất cả các thao tác đều thành công, hoặc không có thao tác nào thành công.rowCount()
: Sau các câu lệnh INSERT
, UPDATE
, DELETE
, sử dụng $stmt->rowCount()
để biết số lượng hàng bị ảnh hưởng. Điều này hữu ích để xác nhận thao tác đã thành công hay chưa.SELECT
các cột bạn cần thay vì SELECT *
.WHERE
và JOIN
có chỉ mục (index) phù hợp để tăng tốc độ truy vấn.Để thực hiện các câu lệnh DDL và DML trong PHP, bạn cần một cầu nối đến hệ quản trị cơ sở dữ liệu (ví dụ: MySQL, PostgreSQL). PHP cung cấp hai extension chính:
mysql
cũ (đã bị loại bỏ).Trong bài viết này, chúng ta đã tập trung vào PDO vì tính linh hoạt và khả năng bảo mật vượt trội của nó (đặc biệt là với prepared statements).
<?php
// Ví dụ kết nối cơ bản với PDO (đặt ở đầu các file PHP tương tác DB)
$host = 'localhost';
$db = 'ten_co_so_du_lieu_cua_ban'; // Đảm bảo CSDL này đã được tạo
$user = 'ten_nguoi_dung';
$pass = 'mat_khau';
$charset = 'utf8mb4';
$dsn = "mysql:host=$host;dbname=$db;charset=$charset";
$options = [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, // Bật chế độ báo lỗi dưới dạng exception
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, // Mặc định trả về mảng kết hợp
PDO::ATTR_EMULATE_PREPARES => false, // Tắt giả lập prepared statements (tăng bảo mật)
];
try {
$pdo = new PDO($dsn, $user, $pass, $options);
// echo "Kết nối cơ sở dữ liệu thành công!";
} catch (\PDOException $e) {
// Nếu kết nối thất bại, dừng ứng dụng và hiển thị lỗi
die("Lỗi kết nối cơ sở dữ liệu: " . $e->getMessage());
}
?>
Việc nắm vững các câu lệnh DDL (CREATE
, ALTER
, DROP
) và DML (SELECT
, INSERT
, UPDATE
, DELETE
) là nền tảng vững chắc cho bất kỳ nhà phát triển PHP nào làm việc với cơ sở dữ liệu. DDL giúp bạn định hình và quản lý cấu trúc dữ liệu, trong khi DML cho phép bạn thao tác với chính dữ liệu đó.
Điều quan trọng nhất là luôn tuân thủ các thực tiễn bảo mật (đặc biệt là phòng chống SQL Injection với prepared statements) và xử lý lỗi hiệu quả để xây dựng các ứng dụng PHP mạnh mẽ, an toàn và đáng tin cậy. Hãy thực hành thường xuyên với các ví dụ này để củng cố kiến thức và kỹ năng của bạn.