JSON trong PHP và MySQL: Đọc, tạo, lưu trữ và xử lý dữ liệu JSON
Bùi Tấn Lực
- 105
- 05/09/2026

JSON là gì và vì sao PHP thường xuyên phải làm việc với JSON?
JSON là một định dạng dữ liệu có cấu trúc, được sử dụng rất phổ biến để trao đổi thông tin giữa website, máy chủ, ứng dụng và các hệ thống bên ngoài. JSON có ưu điểm là gọn, dễ đọc, dễ truyền qua HTTP và đặc biệt phù hợp với PHP khi xây dựng các website có giao tiếp dữ liệu động.
Trong một website PHP, JSON thường xuất hiện ở nhiều vị trí khác nhau. Dữ liệu từ JavaScript gửi lên máy chủ có thể được đóng gói thành JSON. PHP nhận dữ liệu, giải mã thành mảng hoặc đối tượng để xử lý rồi trả kết quả về dưới dạng JSON. Khi website cần giao tiếp với API bên ngoài, JSON cũng thường là định dạng trung gian được sử dụng.
MySQL cũng hỗ trợ kiểu dữ liệu JSON, cho phép lưu trực tiếp các cấu trúc dữ liệu dạng JSON trong cơ sở dữ liệu. Điều này tạo ra một hướng tiếp cận linh hoạt cho những dữ liệu có cấu trúc thay đổi hoặc chứa nhiều thuộc tính phụ.
Tuy nhiên, JSON không phải là lựa chọn thay thế hoàn toàn cho các bảng quan hệ truyền thống. Điểm quan trọng không nằm ở việc sử dụng JSON càng nhiều càng tốt, mà là xác định đúng loại dữ liệu nào nên lưu dưới dạng cột thông thường và dữ liệu nào phù hợp với cấu trúc JSON.
Cấu trúc dữ liệu JSON hoạt động như thế nào?
JSON chủ yếu được xây dựng từ hai dạng cấu trúc là object và array. Object chứa dữ liệu theo cặp khóa và giá trị, trong khi array chứa một danh sách các giá trị theo thứ tự.
Một object JSON thường có dạng gồm các khóa được đặt trong dấu ngoặc kép và giá trị tương ứng. Giá trị có thể là chuỗi, số, true, false, null, một object khác hoặc một array.
Ví dụ, dữ liệu thông tin một sản phẩm có thể được biểu diễn như sau:
{
"name": "Laptop",
"price": 15000000,
"available": true
}
Trong cấu trúc trên, name là chuỗi, price là số và available là giá trị boolean. PHP có thể chuyển cấu trúc này thành mảng để xử lý trong chương trình.
JSON cũng cho phép tạo dữ liệu nhiều tầng. Chẳng hạn một sản phẩm có thể chứa thông tin thương hiệu, danh sách hình ảnh hoặc các thuộc tính kỹ thuật. Đây là điểm khiến JSON phù hợp với những dữ liệu có cấu trúc linh hoạt.
Object và array trong dữ liệu JSON
Object thường được dùng khi dữ liệu có các thuộc tính được đặt tên rõ ràng. Array phù hợp khi cần biểu diễn một danh sách các phần tử.
Ví dụ một sản phẩm có nhiều hình ảnh:
{
"name": "Laptop",
"images": [
"laptop-1.jpg",
"laptop-2.jpg",
"laptop-3.jpg"
]
}
Trong trường hợp này, name là một thuộc tính của object còn images là một array. Khi chuyển dữ liệu sang PHP, cấu trúc lồng nhau này vẫn được giữ lại.
Những kiểu giá trị JSON có thể chứa
JSON hỗ trợ một số kiểu giá trị cơ bản gồm string, number, object, array, boolean và null. Việc hiểu đúng kiểu dữ liệu rất quan trọng khi PHP chuyển đổi qua lại giữa JSON và dữ liệu trong chương trình.
Đặc biệt, cần phân biệt giữa chuỗi chứa ký tự số và số thực tế. Ví dụ "15000000" là chuỗi, trong khi 15000000 là số. Khi dữ liệu được đưa vào MySQL hoặc dùng để tính toán trong PHP, sự khác biệt này có thể ảnh hưởng đến kết quả xử lý.
Chuyển JSON thành dữ liệu PHP bằng json_decode()
Hàm json_decode() là công cụ quan trọng nhất khi PHP cần đọc một chuỗi JSON. Hàm này nhận chuỗi JSON và chuyển nó thành kiểu dữ liệu mà PHP có thể thao tác.
Ở cách sử dụng cơ bản, JSON object có thể được chuyển thành một object PHP:
<?php
$json = '{"name":"Laptop","price":15000000}';
$data = json_decode($json);
echo $data->name;
echo $data->price;
Nếu muốn làm việc với JSON dưới dạng mảng kết hợp, có thể truyền tham số thứ hai là true:
<?php
$json = '{"name":"Laptop","price":15000000}';
$data = json_decode($json, true);
echo $data['name'];
echo $data['price'];
Đối với phần lớn website PHP code tay, việc lựa chọn object hay associative array nên thống nhất theo cách tổ chức của toàn bộ dự án. Không nên cùng một loại dữ liệu nhưng chỗ dùng object, chỗ dùng array nếu không có lý do rõ ràng, vì điều đó dễ làm code khó bảo trì.
Đọc JSON nhiều tầng trong PHP
JSON thực tế thường không đơn giản chỉ có vài trường dữ liệu. Một API có thể trả về thông tin khách hàng, địa chỉ, danh sách đơn hàng và các thuộc tính khác trong cùng một cấu trúc.
Ví dụ:
<?php
$json = '{
"name": "Nguyen Van A",
"address": {
"city": "Ho Chi Minh",
"district": "Quan 10"
}
}';
$data = json_decode($json, true);
echo $data['name'];
echo $data['address']['city'];
echo $data['address']['district'];
Khi dữ liệu được lồng nhiều cấp, cần kiểm tra sự tồn tại của khóa trước khi truy cập nếu dữ liệu đến từ nguồn không hoàn toàn tin cậy. Việc giả định rằng mọi API luôn trả đúng cấu trúc có thể dẫn tới warning, exception hoặc kết quả không đúng.
Tạo JSON từ dữ liệu PHP bằng json_encode()
Nếu json_decode() dùng để đưa JSON vào PHP thì json_encode() thực hiện chiều ngược lại: chuyển array hoặc object PHP thành chuỗi JSON.
Ví dụ:
<?php
$data = [
'name' => 'Laptop',
'price' => 15000000,
'available' => true
];
$json = json_encode($data);
echo $json;
Kết quả sẽ là một chuỗi JSON có cấu trúc tương ứng với dữ liệu PHP ban đầu.
Cách này đặc biệt hữu ích khi PHP cần trả dữ liệu cho JavaScript hoặc một hệ thống khác thông qua API.
Chuyển mảng nhiều tầng thành JSON
PHP có thể chuyển trực tiếp các mảng nhiều tầng sang JSON mà không cần tự xây dựng chuỗi JSON thủ công.
<?php
$product = [
'name' => 'Laptop',
'price' => 15000000,
'images' => [
'laptop-1.jpg',
'laptop-2.jpg'
],
'specifications' => [
'ram' => '16GB',
'storage' => '512GB'
]
];
$json = json_encode($product);
echo $json;
Đây là cách nên ưu tiên thay vì nối chuỗi JSON bằng tay. Việc tự nối chuỗi dễ tạo ra lỗi dấu ngoặc, dấu phẩy, dấu nháy và đặc biệt dễ sai khi dữ liệu chứa ký tự đặc biệt.
Xử lý lỗi khi JSON không hợp lệ
Một trong những lỗi thường gặp khi làm việc với JSON là dữ liệu đầu vào không đúng cú pháp. Chỉ cần thiếu dấu ngoặc kép, dấu phẩy hoặc cấu trúc bị sai, việc giải mã có thể không cho kết quả mong muốn.
Vì vậy, không nên chỉ gọi json_decode() rồi mặc định rằng dữ liệu luôn hợp lệ. PHP cung cấp cơ chế kiểm tra lỗi để xác định nguyên nhân khi quá trình giải mã thất bại.
<?php
$json = '{"name":"Laptop","price":15000000}';
$data = json_decode($json, true);
if (json_last_error() !== JSON_ERROR_NONE) {
echo 'JSON không hợp lệ';
exit;
}
echo $data['name'];
Trong những hệ thống cần kiểm soát lỗi chặt chẽ, có thể sử dụng chế độ ném exception của PHP để việc xử lý lỗi rõ ràng hơn.
<?php
$json = '{"name":"Laptop","price":15000000}';
try {
$data = json_decode(
$json,
true,
512,
JSON_THROW_ON_ERROR
);
echo $data['name'];
} catch (JsonException $e) {
echo 'Dữ liệu JSON không hợp lệ';
}
Cách này đặc biệt hữu ích trong API vì hệ thống có thể chủ động trả về lỗi thay vì tiếp tục xử lý dữ liệu không đúng.
Đọc JSON từ dữ liệu người dùng gửi lên
Trong website hiện đại, PHP có thể nhận JSON trực tiếp từ request HTTP thay vì nhận dữ liệu theo dạng form truyền thống. Trường hợp này thường xuất hiện khi JavaScript, ứng dụng di động hoặc một hệ thống khác gửi request đến API PHP.
Dữ liệu JSON của request thường được đọc từ input stream:
<?php
$input = file_get_contents('php://input');
$data = json_decode($input, true);
if (json_last_error() !== JSON_ERROR_NONE) {
echo 'Dữ liệu gửi lên không hợp lệ';
exit;
}
$name = $data['name'] ?? '';
$price = $data['price'] ?? 0;
Điểm quan trọng là dữ liệu nhận từ client không được mặc định là an toàn. Sau khi giải mã JSON, PHP vẫn phải kiểm tra kiểu dữ liệu, giá trị, độ dài và các điều kiện nghiệp vụ trước khi lưu vào cơ sở dữ liệu.
JSON chỉ là định dạng truyền dữ liệu. Nó không tự động thực hiện việc xác thực dữ liệu, chống SQL injection hay kiểm tra quyền truy cập.
Khi nào nên dùng JSON thay vì mảng PHP?
Array PHP và JSON không phải hai công nghệ cạnh tranh trực tiếp. Array là cấu trúc dữ liệu bên trong chương trình PHP, còn JSON chủ yếu là định dạng biểu diễn và trao đổi dữ liệu.
Trong quá trình xử lý, PHP thường làm việc với array hoặc object. Khi cần truyền dữ liệu ra bên ngoài, dữ liệu đó có thể được chuyển thành JSON. Khi nhận JSON từ bên ngoài, PHP lại giải mã nó thành array hoặc object.
Có thể hình dung quy trình đơn giản như sau:
JSON từ client
↓
PHP đọc request
↓
json_decode()
↓
Array hoặc Object
↓
Xử lý nghiệp vụ
↓
json_encode()
↓
JSON trả về client
Cách hiểu này giúp tránh một sai lầm phổ biến là cố gắng sử dụng JSON như một cấu trúc dữ liệu thay thế cho mọi loại dữ liệu trong PHP.
Chuẩn bị dữ liệu JSON để lưu vào MySQL
Khi dữ liệu cần tồn tại lâu dài, PHP có thể chuyển array thành JSON rồi lưu vào MySQL. Tuy nhiên, trước khi thực hiện, cần xác định dữ liệu đó có thực sự phù hợp để lưu dưới dạng JSON hay không.
Ví dụ một sản phẩm có một nhóm thuộc tính kỹ thuật thay đổi tùy ngành hàng. Một sản phẩm điện thoại có thể có dung lượng pin, kích thước màn hình và camera; trong khi một sản phẩm khác lại có những thuộc tính hoàn toàn khác. Nếu cố đưa tất cả thuộc tính biến động này thành hàng chục cột MySQL, cấu trúc bảng có thể trở nên cồng kềnh.
Trong trường hợp như vậy, một cột JSON có thể là lựa chọn hợp lý để chứa phần dữ liệu linh hoạt.
Ngược lại, những dữ liệu cốt lõi như mã sản phẩm, giá bán, trạng thái, mã khách hàng hoặc thời gian tạo thường nên được thiết kế thành các cột riêng nếu chúng thường xuyên được lọc, sắp xếp, liên kết hoặc thống kê.
Đây là nguyên tắc quan trọng khi kết hợp PHP với MySQL: JSON nên giải quyết phần dữ liệu có cấu trúc linh hoạt, không nên biến toàn bộ cơ sở dữ liệu thành một tập hợp JSON khó truy vấn.
Thiết kế cột JSON trong MySQL đúng cách
MySQL hỗ trợ kiểu dữ liệu JSON riêng biệt, vì vậy khi cần lưu một cấu trúc JSON trong cơ sở dữ liệu, nên sử dụng kiểu JSON thay vì tùy tiện lưu vào TEXT. Kiểu JSON giúp MySQL có khả năng kiểm tra dữ liệu và cung cấp các hàm chuyên dụng để truy cập những giá trị nằm bên trong cấu trúc.
Ví dụ một bảng sản phẩm có thể được thiết kế với thông tin chính nằm ở các cột thông thường và phần thuộc tính linh hoạt nằm trong cột JSON:
CREATE TABLE products (
id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(255) NOT NULL,
price DECIMAL(15,2) NOT NULL DEFAULT 0,
attributes JSON NULL,
created_at DATETIME NOT NULL
);
Cách thiết kế này tạo ra sự cân bằng giữa mô hình quan hệ và dữ liệu linh hoạt. Các thông tin thường xuyên sử dụng trong nghiệp vụ vẫn được quản lý bằng cột riêng, còn những thuộc tính có thể thay đổi được gom vào attributes.
Không nên sử dụng một cột JSON để chứa tất cả thông tin của sản phẩm nếu những thông tin đó có quan hệ rõ ràng với các bảng khác hoặc thường xuyên được dùng để truy vấn. Làm như vậy có thể khiến các thao tác tìm kiếm, thống kê và liên kết dữ liệu trở nên phức tạp hơn nhiều.
JSON trong MySQL khác gì TEXT?
TEXT chỉ xem nội dung được lưu là một chuỗi văn bản. MySQL không hiểu cấu trúc bên trong chuỗi đó theo cách mà kiểu JSON hiểu cấu trúc JSON.
Với cột JSON, MySQL có thể thực hiện các thao tác lấy giá trị theo đường dẫn, kiểm tra cấu trúc và sử dụng nhiều hàm chuyên dụng. Điều này đặc biệt hữu ích khi ứng dụng cần tìm hoặc cập nhật một thuộc tính nằm sâu bên trong dữ liệu.
Do đó, nếu mục đích thực sự là lưu dữ liệu JSON và hệ thống cần truy cập dữ liệu bên trong, kiểu JSON thường phù hợp hơn TEXT.
Lưu dữ liệu JSON từ PHP vào MySQL
Quy trình lưu JSON thường gồm ba bước: xây dựng dữ liệu trong PHP, chuyển dữ liệu thành chuỗi JSON bằng json_encode() và đưa kết quả vào MySQL bằng prepared statement.
Ví dụ với PDO:
<?php
$attributes = [
'ram' => '16GB',
'storage' => '512GB',
'screen' => '15.6 inch'
];
$json = json_encode(
$attributes,
JSON_UNESCAPED_UNICODE | JSON_THROW_ON_ERROR
);
$sql = "INSERT INTO products
(name, price, attributes, created_at)
VALUES
(:name, :price, :attributes, NOW())";
$stmt = $pdo->prepare($sql);
$stmt->execute([
':name' => 'Laptop',
':price' => 15000000,
':attributes' => $json
]);
Điểm đáng chú ý là dữ liệu được truyền thông qua prepared statement. Không nên nối trực tiếp dữ liệu người dùng vào câu SQL chỉ vì nội dung đó sẽ được lưu dưới dạng JSON.
Việc encode JSON và việc bảo vệ câu SQL là hai vấn đề khác nhau. json_encode() giúp tạo ra dữ liệu JSON hợp lệ, còn prepared statement giúp tách dữ liệu khỏi câu lệnh SQL.
Vì sao nên dùng JSON_UNESCAPED_UNICODE?
PHP mặc định có thể escape một số ký tự Unicode khi encode JSON. Với dữ liệu tiếng Việt, sử dụng JSON_UNESCAPED_UNICODE giúp nội dung dễ đọc hơn khi kiểm tra dữ liệu.
<?php
$data = [
'title' => 'Thiết kế website tại Việt Nam'
];
echo json_encode($data);
Có thể kết hợp tùy chọn Unicode:
<?php
$data = [
'title' => 'Thiết kế website tại Việt Nam'
];
echo json_encode(
$data,
JSON_UNESCAPED_UNICODE
);
Việc này chủ yếu giúp biểu diễn dữ liệu dễ đọc hơn. Nó không có nghĩa rằng JSON mặc định không hỗ trợ tiếng Việt.
Đọc dữ liệu JSON từ MySQL bằng PHP
Sau khi lưu dữ liệu, PHP có thể lấy cột JSON từ MySQL rồi sử dụng json_decode() để chuyển nội dung trở lại thành array.
<?php
$sql = "SELECT id, name, price, attributes
FROM products
WHERE id = :id";
$stmt = $pdo->prepare($sql);
$stmt->execute([
':id' => 1
]);
$product = $stmt->fetch(PDO::FETCH_ASSOC);
$attributes = json_decode(
$product['attributes'],
true,
512,
JSON_THROW_ON_ERROR
);
echo $product['name'];
echo $attributes['ram'];
echo $attributes['storage'];
Ở đây có hai lớp dữ liệu khác nhau. Các trường name và price là dữ liệu cột thông thường của MySQL, trong khi attributes chứa một cấu trúc JSON cần được giải mã trước khi PHP sử dụng.
Nếu ứng dụng sử dụng JSON ở nhiều vị trí, nên thống nhất cách decode và xử lý lỗi thay vì rải những đoạn json_decode() giống nhau khắp mã nguồn.
Truy vấn trực tiếp giá trị bên trong JSON bằng MySQL
Một trong những ưu điểm đáng giá của kiểu JSON là không nhất thiết phải lấy toàn bộ JSON về PHP rồi mới tìm dữ liệu. MySQL có thể truy cập trực tiếp một thuộc tính nằm bên trong JSON.
Giả sử cột attributes chứa:
{
"ram": "16GB",
"storage": "512GB",
"screen": "15.6 inch"
}
Có thể lấy giá trị ram bằng toán tử đường dẫn:
SELECT
id,
name,
attributes->'$.ram' AS ram
FROM products;
Nếu muốn nhận giá trị dưới dạng chuỗi đã được bỏ lớp JSON string, có thể sử dụng toán tử ->>:
SELECT
id,
name,
attributes->>'$.ram' AS ram
FROM products;
Sự khác nhau giữa hai cách này rất quan trọng khi xây dựng truy vấn. -> trả về giá trị theo biểu diễn JSON, trong khi ->> trả về giá trị đã được trích xuất dưới dạng chuỗi.
Truy cập JSON nhiều cấp
Dữ liệu JSON có thể chứa object bên trong object. Khi đó đường dẫn JSON sẽ thể hiện từng cấp của cấu trúc.
Ví dụ:
{
"seo": {
"title": "Laptop chính hãng",
"description": "Thông tin sản phẩm"
}
}
Truy vấn thuộc tính title:
SELECT
attributes->>'$.seo.title' AS seo_title
FROM products;
Cách tổ chức đường dẫn rõ ràng giúp MySQL lấy đúng dữ liệu mà không cần đưa toàn bộ JSON về PHP.
Tìm sản phẩm theo một thuộc tính JSON
Giả sử website cần tìm những sản phẩm có RAM là 16GB. Có thể truy vấn trực tiếp giá trị nằm trong JSON:
SELECT
id,
name,
price
FROM products
WHERE attributes->>'$.ram' = '16GB';
Cách này phù hợp với những trường hợp số lượng dữ liệu vừa phải hoặc thuộc tính chỉ được sử dụng ở mức bổ trợ.
Tuy nhiên, khi một thuộc tính JSON được dùng thường xuyên trong các truy vấn lớn, việc chỉ viết đường dẫn JSON trong câu WHERE chưa chắc đã là giải pháp tối ưu. Khi đó cần xem xét indexing hoặc đưa thuộc tính quan trọng thành cột riêng.
Cập nhật một thuộc tính mà không cần ghi đè toàn bộ JSON
Một lỗi thiết kế dễ gặp là lấy toàn bộ JSON về PHP, sửa một giá trị rồi ghi cả cấu trúc trở lại MySQL cho một thay đổi rất nhỏ.
MySQL cung cấp các hàm JSON để cập nhật trực tiếp một phần dữ liệu. Ví dụ thay đổi dung lượng RAM:
UPDATE products
SET attributes = JSON_SET(
attributes,
'$.ram',
'32GB'
)
WHERE id = 1;
Trong trường hợp này, ứng dụng không cần đọc toàn bộ JSON về PHP chỉ để thay đổi một thuộc tính.
Điều này đặc biệt hữu ích khi JSON chứa nhiều dữ liệu hoặc khi website có nhiều request cập nhật các thuộc tính nhỏ.
Thêm thuộc tính mới vào cấu trúc
JSON_SET() cũng có thể được dùng để thêm một khóa chưa tồn tại:
UPDATE products
SET attributes = JSON_SET(
attributes,
'$.color',
'Black'
)
WHERE id = 1;
Nếu khóa color chưa tồn tại, MySQL sẽ bổ sung nó. Nếu khóa đã tồn tại, giá trị có thể được thay thế.
Đây là điểm khác biệt quan trọng giữa dữ liệu JSON và một tập hợp cột cố định: cấu trúc có thể mở rộng mà không nhất thiết phải ALTER TABLE mỗi khi xuất hiện một thuộc tính mới.
Xóa một thuộc tính khỏi JSON
Khi một thuộc tính không còn cần thiết, MySQL có thể xóa trực tiếp khóa đó bằng JSON_REMOVE().
UPDATE products
SET attributes = JSON_REMOVE(
attributes,
'$.color'
)
WHERE id = 1;
Nếu dữ liệu có cấu trúc nhiều tầng, đường dẫn cũng có thể trỏ đến vị trí cụ thể cần xóa.
Việc cập nhật trực tiếp như vậy giúp hạn chế lượng dữ liệu phải truyền qua lại giữa PHP và MySQL, đặc biệt khi ứng dụng chỉ thay đổi một phần nhỏ trong cấu trúc.
Kiểm tra dữ liệu trước khi lưu vào cơ sở dữ liệu
Việc JSON hợp lệ về mặt cú pháp không đồng nghĩa với việc dữ liệu bên trong hợp lệ về mặt nghiệp vụ.
Ví dụ:
{
"price": -5000000,
"quantity": "abc"
}
Cấu trúc trên vẫn có thể là JSON hợp lệ, nhưng rõ ràng không phù hợp nếu đây là dữ liệu sản phẩm. Vì vậy, PHP cần thực hiện bước validation trước khi encode và lưu dữ liệu.
Có thể kiểm tra từng trường theo nghiệp vụ:
<?php
$attributes = [
'ram' => trim($input['ram'] ?? ''),
'storage' => trim($input['storage'] ?? ''),
'quantity' => (int) ($input['quantity'] ?? 0)
];
if ($attributes['quantity'] < 0) {
throw new RuntimeException('Số lượng không hợp lệ');
}
$json = json_encode(
$attributes,
JSON_UNESCAPED_UNICODE | JSON_THROW_ON_ERROR
);
Quy trình tốt nên được hiểu theo thứ tự: nhận dữ liệu → kiểm tra dữ liệu → chuẩn hóa dữ liệu → encode JSON → lưu database. Không nên xem JSON là một lớp validation.
Không nên lưu mọi thứ vào một cột JSON
JSON mang lại sự linh hoạt nhưng cũng dễ bị lạm dụng. Nếu một website có bảng đơn hàng với khách hàng, sản phẩm, số lượng, giá, trạng thái và lịch sử giao dịch, việc nhét toàn bộ thông tin vào một cột JSON sẽ làm mất nhiều lợi thế của cơ sở dữ liệu quan hệ.
Những dữ liệu có các đặc điểm sau thường nên cân nhắc để thành cột hoặc bảng riêng:
- Dữ liệu thường xuyên được tìm kiếm.
- Dữ liệu thường xuyên được sắp xếp hoặc lọc.
- Dữ liệu cần thống kê, tính tổng hoặc báo cáo.
- Dữ liệu có quan hệ rõ ràng với một bảng khác.
- Dữ liệu cần ràng buộc chặt chẽ về kiểu và tính toàn vẹn.
JSON phù hợp hơn với các thuộc tính phụ, cấu hình, metadata hoặc những cấu trúc có số lượng trường thay đổi tùy từng bản ghi.
Thiết kế tốt không phải là chọn JSON hay bảng quan hệ cho toàn bộ hệ thống. Cách hiệu quả hơn là để mỗi loại dữ liệu nằm ở nơi phù hợp với cách ứng dụng sử dụng nó.
Tối ưu truy vấn khi dữ liệu JSON ngày càng lớn
Khi website mới có vài trăm hoặc vài nghìn bản ghi, việc truy cập thuộc tính bên trong JSON thường chưa tạo ra vấn đề rõ rệt. Nhưng khi dữ liệu tăng lên đáng kể, các truy vấn JSON được thiết kế thiếu tính toán có thể trở thành điểm nghẽn.
Đặc biệt, nếu một thuộc tính nằm trong JSON thường xuyên xuất hiện trong điều kiện WHERE, ORDER BY hoặc được sử dụng để lọc một lượng lớn bản ghi, cần đánh giá lại cách lưu trữ thay vì chỉ tiếp tục bổ sung logic xử lý trong PHP.
Nguyên tắc quan trọng là xác định những trường nào thực sự tham gia vào nghiệp vụ chính. Nếu một giá trị trở thành tiêu chí tìm kiếm thường xuyên, nó có thể không còn phù hợp với vị trí nằm sâu trong JSON.
Khi nào cần tạo index cho dữ liệu JSON?
Không phải mọi thuộc tính trong JSON đều cần index. Việc tạo index chỉ đáng cân nhắc đối với những dữ liệu thường xuyên được sử dụng trong truy vấn và có khả năng giúp MySQL giảm lượng bản ghi phải kiểm tra.
Ví dụ, nếu website liên tục tìm sản phẩm theo một thuộc tính cụ thể, có thể tạo một cột sinh ra từ giá trị JSON rồi đánh index cho cột đó.
ALTER TABLE products
ADD COLUMN ram_value VARCHAR(50)
GENERATED ALWAYS AS (
JSON_UNQUOTE(attributes->'$.ram')
) STORED;
CREATE INDEX idx_products_ram
ON products (ram_value);
Cách tiếp cận này giúp giữ dữ liệu gốc trong JSON nhưng đồng thời tạo ra một giá trị có thể được index riêng.
Đây là giải pháp hữu ích khi thuộc tính vẫn mang tính linh hoạt nhưng một vài trường bên trong JSON lại có vai trò quan trọng đối với hiệu năng truy vấn.
Không nên dùng PHP để lọc toàn bộ dữ liệu khi MySQL có thể xử lý
Một cách làm kém hiệu quả là lấy hàng nghìn hoặc hàng chục nghìn bản ghi từ MySQL về PHP, sau đó dùng json_decode() để duyệt từng bản ghi và tìm những dữ liệu phù hợp.
Ví dụ, nếu cần tìm sản phẩm có RAM 16GB, không nên lấy toàn bộ sản phẩm về rồi lọc bằng PHP nếu MySQL có thể thực hiện điều kiện đó ngay trong câu SQL.
SELECT
id,
name,
price
FROM products
WHERE attributes->>'$.ram' = '16GB';
Đưa điều kiện lọc xuống database thường giúp giảm lượng dữ liệu truyền từ MySQL sang PHP. PHP chỉ nhận những bản ghi cần thiết để tiếp tục xử lý.
Tuy nhiên, điều này không có nghĩa mọi phép xử lý JSON đều phải thực hiện ở MySQL. Những nghiệp vụ phức tạp thuộc về logic ứng dụng vẫn nên được xử lý ở PHP. Mục tiêu là phân chia công việc hợp lý giữa database và application.
Trả dữ liệu JSON từ PHP cho JavaScript
JSON phát huy giá trị rõ ràng nhất khi PHP đóng vai trò máy chủ API và JavaScript là phía nhận dữ liệu. PHP có thể lấy dữ liệu từ MySQL, xử lý rồi trả về một response JSON.
Ví dụ một API đơn giản:
<?php
header('Content-Type: application/json; charset=utf-8');
$response = [
'success' => true,
'message' => 'Lấy dữ liệu thành công',
'data' => [
'name' => 'Laptop',
'price' => 15000000
]
];
echo json_encode(
$response,
JSON_UNESCAPED_UNICODE
);
Phía JavaScript có thể nhận response và sử dụng dữ liệu mà không cần xử lý HTML do PHP sinh trực tiếp.
Một cấu trúc response nhất quán cũng rất quan trọng. Thay vì API này trả một object, API khác trả một array và API khác lại trả chuỗi lỗi, nên thống nhất cấu trúc response để frontend dễ xử lý.
Ví dụ có thể duy trì ba thành phần cơ bản là trạng thái thành công, thông báo và dữ liệu.
Xử lý JSON khi nhận dữ liệu từ JavaScript
Chiều ngược lại cũng rất phổ biến: JavaScript gửi JSON lên PHP để tạo hoặc cập nhật dữ liệu.
PHP có thể lấy nội dung request từ php://input, sau đó giải mã JSON:
<?php
header('Content-Type: application/json; charset=utf-8');
$input = file_get_contents('php://input');
try {
$data = json_decode(
$input,
true,
512,
JSON_THROW_ON_ERROR
);
} catch (JsonException $e) {
http_response_code(400);
echo json_encode([
'success' => false,
'message' => 'Dữ liệu JSON không hợp lệ'
]);
exit;
}
Sau bước decode, PHP vẫn phải kiểm tra dữ liệu trước khi thực hiện nghiệp vụ. Không nên lấy trực tiếp các giá trị nhận được rồi đưa vào câu SQL hoặc dùng chúng để thay đổi dữ liệu quan trọng.
JSON không thay thế cho validation và bảo mật
JSON chỉ mô tả cách dữ liệu được đóng gói. Nó không đảm bảo rằng dữ liệu đó an toàn hay đúng nghiệp vụ.
Ví dụ một request hoàn toàn có thể chứa các giá trị sai kiểu, thiếu trường bắt buộc hoặc chứa dữ liệu vượt giới hạn cho phép. PHP cần kiểm tra tất cả những điều này trước khi tiếp tục.
Đối với database, nên sử dụng prepared statement:
<?php
$sql = "UPDATE products
SET name = :name,
price = :price,
attributes = :attributes
WHERE id = :id";
$stmt = $pdo->prepare($sql);
$stmt->execute([
':name' => $name,
':price' => $price,
':attributes' => $json,
':id' => $id
]);
Prepared statement không chỉ dành cho dữ liệu dạng chuỗi thông thường. Dữ liệu JSON cũng phải được truyền vào SQL theo cách an toàn.
Ngoài SQL injection, ứng dụng còn phải quan tâm đến quyền truy cập. Một người dùng không có quyền sửa sản phẩm thì dù request JSON có hợp lệ đến đâu, PHP vẫn phải từ chối thao tác.
Xử lý JSON chứa tiếng Việt và ký tự đặc biệt
Dữ liệu tiếng Việt thường xuất hiện trong website PHP như tên sản phẩm, mô tả, địa chỉ, nội dung SEO hoặc thông tin khách hàng. JSON hỗ trợ Unicode nên không cần chuyển tiếng Việt thành một định dạng đặc biệt trước khi encode.
Có thể sử dụng:
<?php
$data = [
'title' => 'Thiết kế website chuẩn SEO',
'description' => 'Website dành cho doanh nghiệp Việt Nam'
];
$json = json_encode(
$data,
JSON_UNESCAPED_UNICODE | JSON_THROW_ON_ERROR
);
Điều quan trọng hơn là toàn bộ hệ thống PHP và MySQL phải sử dụng encoding phù hợp, đặc biệt khi kết nối database. Với MySQL hiện đại, utf8mb4 thường là lựa chọn nên dùng để hỗ trợ Unicode đầy đủ.
Xử lý null và giá trị không tồn tại trong JSON
Một JSON thực tế có thể thiếu thuộc tính hoặc có thuộc tính mang giá trị null. PHP cần phân biệt giữa hai trường hợp này nếu nghiệp vụ yêu cầu.
Ví dụ:
<?php
$data = json_decode($json, true);
$color = $data['color'] ?? null;
if ($color === null) {
echo 'Chưa có màu sản phẩm';
}
Cách viết này giúp tránh warning khi khóa không tồn tại. Tuy nhiên, nếu ứng dụng cần phân biệt rõ giữa không có khóa và khóa tồn tại nhưng có giá trị null, cần kiểm tra sự tồn tại của khóa một cách riêng biệt.
Việc thống nhất quy ước dữ liệu từ đầu sẽ giúp API và database dễ bảo trì hơn. Ví dụ, cần xác định trường nào bắt buộc, trường nào có thể null và trường nào sẽ không xuất hiện nếu không có dữ liệu.
JSON phù hợp với những loại dữ liệu nào?
JSON đặc biệt hữu ích đối với những dữ liệu có cấu trúc linh hoạt nhưng vẫn cần giữ nguyên mối quan hệ giữa các thuộc tính.
- Thuộc tính mở rộng của sản phẩm.
- Cấu hình riêng của từng website hoặc từng tài khoản.
- Metadata của nội dung.
- Dữ liệu tùy chọn của biểu mẫu.
- Thông tin bổ sung từ API bên ngoài.
- Cấu hình giao diện hoặc tính năng có nhiều biến thể.
Ví dụ một hệ thống bán nhiều loại sản phẩm có thể lưu các thông số kỹ thuật biến động trong một cột JSON thay vì phải tạo một bảng với quá nhiều cột ít được sử dụng.
Những trường hợp không nên sử dụng JSON
JSON không phải giải pháp tốt khi dữ liệu cần quan hệ chặt chẽ và thường xuyên tham gia vào các phép truy vấn quan hệ.
- Danh sách khách hàng cần tìm kiếm thường xuyên.
- Đơn hàng cần thống kê theo thời gian.
- Sản phẩm cần lọc và sắp xếp theo nhiều tiêu chí chính.
- Dữ liệu cần liên kết bằng khóa ngoại.
- Dữ liệu cần tổng hợp với số lượng lớn.
- Thông tin có cấu trúc cố định và được sử dụng ở hầu hết truy vấn.
Ví dụ, nếu website cần thống kê doanh thu theo khách hàng, thời gian và sản phẩm, việc đưa toàn bộ đơn hàng vào JSON sẽ làm các truy vấn báo cáo phức tạp hơn rất nhiều so với việc thiết kế các bảng quan hệ phù hợp.
JSON nên được xem là một công cụ bổ sung cho mô hình dữ liệu, không phải cách để né tránh việc thiết kế database.
Những lỗi thường gặp khi lập trình JSON với PHP và MySQL
Tự nối chuỗi JSON bằng tay
Việc tự nối chuỗi JSON thường dễ phát sinh lỗi khi dữ liệu có dấu nháy kép, ký tự xuống dòng hoặc ký tự đặc biệt. Nên tạo array hoặc object trong PHP rồi sử dụng json_encode().
Không kiểm tra lỗi khi decode
Ứng dụng không nên mặc định rằng JSON nhận từ client hoặc API bên ngoài luôn hợp lệ. Hãy kiểm tra lỗi sau khi decode hoặc sử dụng JSON_THROW_ON_ERROR khi phù hợp.
Lưu toàn bộ database vào một JSON
Việc gom nhiều loại dữ liệu quan hệ vào một cột JSON có thể làm hệ thống nhanh chóng trở nên khó truy vấn, khó bảo trì và khó thống kê.
Dùng JSON để thay thế mọi cột database
Nếu một giá trị thường xuyên được tìm kiếm, lọc, sắp xếp hoặc liên kết với bảng khác, nên xem xét đưa nó thành cột riêng.
Không dùng prepared statement
JSON không làm cho dữ liệu trở nên an toàn trước SQL injection. Câu SQL vẫn phải được xây dựng và thực thi theo các nguyên tắc bảo mật thông thường.
Quy trình xử lý JSON hiệu quả trong một website PHP
Một quy trình rõ ràng sẽ giúp việc xử lý JSON dễ kiểm soát hơn khi dự án phát triển.
- Nhận dữ liệu từ form, JavaScript hoặc API.
- Kiểm tra request và quyền truy cập.
- Giải mã JSON nếu dữ liệu đầu vào ở dạng JSON.
- Kiểm tra kiểu dữ liệu và điều kiện nghiệp vụ.
- Chuẩn hóa dữ liệu trước khi lưu.
- Encode dữ liệu PHP thành JSON khi cần lưu vào cột JSON.
- Thực hiện truy vấn MySQL bằng prepared statement.
- Lấy dữ liệu từ database theo đúng nhu cầu.
- Giải mã JSON khi PHP cần thao tác với dữ liệu bên trong.
- Encode response khi cần trả dữ liệu cho client.
Quy trình này giúp phân tách rõ nhiệm vụ giữa PHP, MySQL và phía client. Khi có lỗi, lập trình viên cũng dễ xác định lỗi nằm ở bước nhận dữ liệu, validation, encode, database hay response.
JSON trong PHP và MySQL nên được sử dụng như thế nào trong dự án thực tế?
Điểm mạnh nhất của JSON là khả năng chứa dữ liệu có cấu trúc linh hoạt mà không bắt buộc database phải thay đổi schema liên tục. PHP lại cung cấp sẵn những công cụ thuận tiện để encode và decode dữ liệu, trong khi MySQL có khả năng lưu trữ và truy vấn trực tiếp cấu trúc JSON.
Tuy nhiên, hiệu quả của giải pháp phụ thuộc chủ yếu vào cách thiết kế dữ liệu. Một website có thể sử dụng JSON rất tốt nếu chỉ đưa những thuộc tính thực sự linh hoạt vào đó. Ngược lại, một hệ thống có thể trở nên khó bảo trì nếu sử dụng JSON như nơi chứa tất cả dữ liệu chỉ vì cách này ban đầu có vẻ đơn giản.
Với website PHP code tay, cách tiếp cận hợp lý là giữ các dữ liệu nghiệp vụ cốt lõi ở dạng quan hệ rõ ràng, đồng thời tận dụng JSON cho phần thông tin mở rộng. Khi một thuộc tính trong JSON dần trở thành tiêu chí quan trọng của hệ thống, có thể cân nhắc đưa nó thành cột riêng hoặc xây dựng cơ chế index phù hợp.
Kết luận
JSON trong PHP và MySQL không chỉ đơn giản là việc gọi json_encode() và json_decode(). Để sử dụng hiệu quả, lập trình viên cần hiểu cả vòng đời của dữ liệu: từ lúc nhận request, kiểm tra, chuyển đổi, lưu vào MySQL, truy vấn, cập nhật cho đến khi trả kết quả về client.
PHP giúp xử lý JSON thuận tiện ở tầng ứng dụng, còn MySQL đảm nhận việc lưu trữ và truy vấn những dữ liệu JSON phù hợp. Khi hai thành phần được phân chia đúng trách nhiệm, JSON có thể giải quyết rất tốt những bài toán mà cấu trúc bảng cố định khó đáp ứng.
Ngược lại, nếu sử dụng JSON để thay thế cho mọi cấu trúc quan hệ, hệ thống có thể gặp khó khăn về truy vấn, index, thống kê và bảo trì khi dữ liệu phát triển.
Vì vậy, nguyên tắc quan trọng nhất không phải là “có nên dùng JSON hay không”, mà là “dữ liệu nào nên dùng JSON và dữ liệu nào nên giữ ở cấu trúc quan hệ”. Đây mới là quyết định ảnh hưởng trực tiếp đến khả năng mở rộng và chất lượng của một website PHP/MySQL.
- 0 Bình luận
Email, Điện thoại của bạn sẽ không được hiển thị công khai. Các trường bắt buộc được đánh dấu *