首頁 >後端開發 >php教程 >想做一個用戶量非常小的網站,資料儲存要怎麼選?

想做一個用戶量非常小的網站,資料儲存要怎麼選?

WBOY
WBOY原創
2016-08-04 09:19:20962瀏覽

想做一個用戶量非常小的網站,用戶數量幾人到十幾人左右,這個用戶量真的非常小了。
後端用php,現在想知道資料儲存該怎麼做。

因為使用者量很小,所以主機配置也會很低,使用mysql感覺既大材小用,且可能會因為主機配置太低影響效能。

考慮過直接存到文件裡(資料都是比較簡單的結構,json都能搞定),但是這樣的話如果有關聯查詢(比如mysql的join),那就都要用php自己做關聯查詢了,感覺有些麻煩。

有沒有什麼更好的辦法?例如超輕量級的資料庫?

PS:redis這些就不要了,因為主機配置低,記憶體一定吃緊。像mysql和redis這種大力出奇蹟的沒辦法在這種邋遢環境下發揮實力。

回覆內容:

想做一個用戶量非常小的網站,用戶數量幾人到十幾人左右,這個用戶量真的非常小了。
後端用php,現在想知道資料儲存該怎麼做。

因為使用者量很小,所以主機配置也會很低,使用mysql感覺既大材小用,且可能會因為主機配置太低影響效能。

考慮過直接存到文件裡(資料都是比較簡單的結構,json都能搞定),但是這樣的話如果有關聯查詢(比如mysql的join),那就都要用php自己做關聯查詢了,感覺有些麻煩。

有沒有什麼更好的辦法?例如超輕量級的資料庫?

PS:redis這些就不要了,因為主機配置低,記憶體一定吃緊。像mysql和redis這種大力出奇蹟的沒辦法在這種邋遢環境下發揮實力。

用SQLite,或乾脆文件存儲,文件儲存的話,資料檔放到webroot之外。

樓上正解,sqlite.輕量級的,不需要服務,文件即可,之前參與過研發的專案客戶端就用到了sqlite

還是mysql,檔案讀寫的效率比使用mysql更低,而且你開發的時候也會額外增加困難。建議你先試試,主機配置再低會低過樹莓派嗎?當然,如果主機配置本來就低還非要裝windows就沒轍了。

如果你是用orm開發,前期選數據庫並不是你要考慮的東西
如果是你寫sql開發,那你就要考慮如果以​​後數據庫換了,你寫的sql並不一定能兼容

主機配置再低,也沒有你想像的那麼誇張,像mysql,postgres肯定是可以跑得動的

推薦SQLite,PHP自帶擴展,雖然功能和資料類型上比起MySQL要簡單得多,但常用的都沒問題,而且效能也非常不錯。

你用SQLite的話,資料檔最好不要放在網站根目錄,否則人家知道URL就下載了.
當然你可以配置Apache/Nginx deny掉訪問指定文件的請求,但終歸還是個隱患,
所以還是放網站根目錄外吧.
另外你用SQLite的話,你還要寫SQL語言,還要用PDO那一套函數來操作:

<code><?php

function db() {
    static $db;
    if ($db) {
        return $db;
    } else {
        try {
            $db = new PDO('sqlite:'.$_SERVER['DOCUMENT_ROOT'].'/../data.db3');
        } catch (PDOException $e) {
            echo $e->getMessage();
            exit();
        }
        return $db;
    }
}

function insert($title = '', $content = '') {
    global $app;
    $db = db();
    $stmt = $db->prepare('INSERT INTO posts (post_title, post_content) VALUES (?, ?)');
    $stmt->bindParam(1, $title,   PDO::PARAM_STR);
    $stmt->bindParam(2, $content, PDO::PARAM_STR);
    $stmt->execute();
    return ($stmt->rowCount() !== 0) ? 
        array(true,  'lastInsertId' => $db->lastInsertId()) : 
        array(false, 'lastInsertId' => $db->lastInsertId());
}

function select($id = '') {
    global $app;
    $db = db();
    if (!empty($id)) {
        return $db->query('SELECT * FROM posts WHERE id = '.intval($id))->fetchAll(PDO::FETCH_ASSOC);
    } else {
        return $db->query('SELECT * FROM posts')->fetchAll(PDO::FETCH_ASSOC);
    }
}

function select_v2($id = '') {
    global $app;
    $db = db();
    if (!empty($id)) {
        $stmt = $db->prepare('SELECT * FROM posts WHERE id = ?');
        $stmt->bindParam(1, $id, PDO::PARAM_INT);
    } else {
        $stmt = $db->prepare('SELECT * FROM posts');
    }
    $stmt->execute();
    return $stmt->fetchAll(PDO::FETCH_ASSOC);
}

function update($id, $title = '', $content = '') {
    global $app;
    $db = db();
    
    //echo PDO::ATTR_AUTOCOMMIT; //返回0可见PDO默认禁用自动提交事务.
    //echo $db->getAttribute(PDO::ATTR_AUTOCOMMIT); exit(); //返回1可见MySQL默认会自动提交事务.
    
    //SQLite不支持设置PDO::ATTR_AUTOCOMMIT:
    //SQLite: Uncaught exception 'PDOException' with message 'The auto-commit mode cannot be changed for this driver'
    //$db->setAttribute(PDO::ATTR_AUTOCOMMIT, false);
    $db->beginTransaction();
    $stmt = $db->prepare('UPDATE posts SET post_title = ?, post_content = ? WHERE id = ?');
    
    $stmt->execute(array($title,$content,$id)); //所有值视作PDO::PARAM_STR处理
    //$stmt->execute(array(':title' => $title,':content' => $content,':id' => $id));
    //$stmt->bind_param('ssi', $title, $content, $id); //对比mysqli
    
    echo 'sleep(3);'."\n";
    sleep(3);
    
    $db->commit();
    //$db->setAttribute(PDO::ATTR_AUTOCOMMIT, true); //commit提交事务后autocommit记得重新设为true
    return ($stmt->rowCount() !== 0) ? true : false;
}

function delete($id) {
    global $app;
    $db = db();
    return ($db->query('DELETE FROM posts WHERE id = '.intval($id))->rowCount() !== 0) ? true : false;
}

function delete_v2($id) {
    global $app;
    $db = db();
    $stmt = $db->prepare('DELETE FROM posts WHERE id = ?');
    $stmt->bindParam(1, $id, PDO::PARAM_INT);
    $stmt->execute();
    return ($stmt->rowCount() !== 0) ? true : false;
}

header('Content-Type: text/plain; charset=utf-8');

$sqlite = "CREATE TABLE IF NOT EXISTS posts (
    id           INTEGER PRIMARY KEY,
    post_title   VARCHAR(255) NOT NULL,
    post_content TEXT         NOT NULL
)";

db()->query('DROP TABLE IF EXISTS posts;') or exit();
db()->query($sqlite) or exit();

//并发时,SQLite在insert时因为库文件被其他请求锁住而导致阻塞
echo "var_export(insert('标题1', '内容1'));\n";
var_export(insert('标题1', '内容1'));
echo "\n\n";

echo "var_export(insert('标题2', '内容2'));\n";
var_export(insert('标题2', '内容2'));
echo "\n\n";

echo "var_export(select());\n";
var_export(select());
echo "\n\n";

echo "var_export(update(2, '标题2_更新','内容2_更新'));\n";
var_export(update(2, '标题2_更新','内容2_更新'));
echo "\n\n";

echo "var_export(select(2));\n";
var_export(select(2));
echo "\n\n";

echo "var_export(delete(2));\n";
var_export(delete(2));
echo "\n\n";

echo "var_export(select());\n";
var_export(select());
echo "\n\n";</code>

不知大家有沒有這樣一種體會,PHP其實是一門面向數組編程的語言.
其實你可以考慮直接用PHP數組導出成文件來存儲數據.

<code><?php
header('Content-Type: text/plain; charset=utf-8');
$file = __DIR__.'/data.php'; //数据文件,别人直接URL访问也下载不了
if(!file_exists($file)) {
    file_put_contents($file, '<?php return array();'); //file_put_contents($file, '');
}
$fp = fopen($file, 'r+'); //读写方式打开,将文件指针指向文件头
if(flock($fp, LOCK_EX)) { //阻塞到获取排它锁
    //锁定数据文件后再进行读写
    $arr = require $file; //$arr = unserialize(file_get_contents($file));
    $arr[] = date('Y-m-d H:i:s');
    ftruncate($fp, 0); //清空文件
    fwrite($fp, '<?php return '.var_export($arr, true).';'); //fwrite($fp, serialize($arr));
    fflush($fp); //在释放锁之前刷新输出
    //sleep(10); //睡眠10秒,在此期间其他工作进程的请求将被阻塞
    flock($fp, LOCK_UN); //释放锁定
    echo file_get_contents($file)."\n";
}
fclose($fp);</code>

註釋裡還提供了像PHP會話那樣serialize/unserialize序列化存儲的方法.
值得一說的是,serialize/unserialize的性能要比var_export/require好得多.
不過var_export/require的優勢在於不怕別人直接存取,可以把檔案放根目錄,而且可讀性更好.

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn