首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> PHP 程式設計 >> PHP 相關知識

PHP + MySQL + Ajax 實現點贊功能完整實例

     編輯:PHP 相關知識

PHP + MySQL + Ajax 實現點贊功能完整實例

前後端分離架構下,點贊功能典型流程:前端攔截點擊 → Ajax 請求後端 → 後端驗證 Cookie/Session → 更新資料庫 → 返回新計數 → 前端更新顯示。本文提供完整可運行代碼。

資料庫表結構

CREATE TABLE `good` (
  `id` INT UNSIGNED PRIMARY KEY AUTO_INCREMENT,
  `value` INT UNSIGNED NOT NULL DEFAULT 0 COMMENT '贊數'
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

INSERT INTO `good` (`id`, `value`) VALUES (1,0),(2,0),(3,0),(4,0);

後端 API (like.php)

<?php
header('Content-Type: application/json; charset=utf-8');

$pdo = new PDO('mysql:host=localhost;dbname=test;charset=utf8mb4', 'root', '', [
    PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
    PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
]);

$action = $_GET['action'] ?? 'get'; // get | incr
$id = (int)($_GET['id'] ?? 0);
$cookieKey = "like_{$id}";

if ($action === 'get') {
    $stmt = $pdo->prepare('SELECT value FROM `good` WHERE id=?');
    $stmt->execute([$id]);
    echo json_encode(['count' => (int)($stmt->fetchColumn() ?? 0)]);
    return;
}

if ($action === 'incr') {
    // 簡易防重:Cookie 存儲 (生產環境建議 Redis + 用戶ID)
    if (isset($_COOKIE[$cookieKey])) {
        http_response_code(409);
        echo json_encode(['error' => 'Already liked']);
        return;
    }

    $pdo->beginTransaction();
    try {
        $stmt = $pdo->prepare('UPDATE `good` SET value = value + 1 WHERE id=?');
        $stmt->execute([$id]);
        $stmt = $pdo->prepare('SELECT value FROM `good` WHERE id=?');
        $stmt->execute([$id]);
        $newCount = (int)$stmt->fetchColumn();
        $pdo->commit();

        // 設定 Cookie 1 年
        setcookie($cookieKey, '1', time() + 3600*24*365, '/', '', false, true);
        echo json_encode(['count' => $newCount]);
    } catch (Exception $e) {
        $pdo->rollBack();
        http_response_code(500);
        echo json_encode(['error' => 'Server error']);
    }
    return;
}

http_response_code(400);
echo json_encode(['error' => 'Invalid action']);

前端頁面 (index.html)

<!DOCTYPE html>
<html><head><meta charset="utf-8"><title>點贊 Demo</title></head><body>
<div id="likes">
  <span data-id="1">0</span> <button data-id="1">贊+1</button><br>
  <span data-id="2">0</span> <button data-id="2">贊+1</button><br>
  <span data-id="3">0</span> <button data-id="3">贊+1</button><br>
  <span data-id="4">0</span> <button data-id="4">贊+1</button>
</div>

<script>
document.addEventListener('DOMContentLoaded', () => {
  // 初始載入
  document.querySelectorAll('#likes span[data-id]').forEach(loadCount);

  // 綁定點擊
  document.querySelectorAll('#likes button[data-id]').forEach(btn => {
    btn.addEventListener('click', () => increment(btn.dataset.id));
  });
});

function loadCount(span) {
  fetch(`like.php?action=get&id=${span.dataset.id}`)
    .then(r => r.json())
    .then(d => span.textContent = d.count)
    .catch(console.error);
}

function increment(id) {
  fetch(`like.php?action=incr&id=${id}`)
    .then(r => {
      if (r.status === 409) return r.json().then(d => { throw d.error; });
      if (!r.ok) throw new Error('Network error');
      return r.json();
    })
    .then(d => {
      document.querySelector(`#likes span[data-id="${id}"]`).textContent = d.count;
      alert('點贊成功!');
    })
    .catch(err => alert(err || '已點過贊'));
}
</script>
</body></html>

關鍵點總結

  • PDO 預處理:防 SQL 注入,效能優於 mysql_* (已棄用)。
  • 事務包裹:更新與查詢原子化,避免併發下髒讀。
  • Cookie 防重:簡單場景可用;登入系統應改用 user_id + item_id 唯一索引 + Redis Set 判斷。
  • RESTful 風格:GET /like?id=1 讀取、POST /like {id:1} 增加,語義更清晰。
  • 錯誤碼語義化:409 Conflict 表示重複點贊,前端據此提示。

進階優化方向

  1. Redis INCR 計數 + 定時持久化落庫,抗高併發。
  2. 用戶點贊記錄表 user_likes (user_id, item_id, created_at),唯一索引防重,支援取消點贊。
  3. 前端樂觀 UI:點擊即時 +1,請求失敗回滾,提升體感速度。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved