當用戶量非常大,需要多台服務器女算提供應用的時(shí)候,使用MySQ有南L存儲會(huì)話相對(duì)使用會(huì)話文年就件具有一定的優越性。比如具有最小的存儲開(kāi)銷,務有比如可以避免文件共享帶來的複雜性中事,比如可以更好(hǎo)的避免發(fā)生碰撞,比如相比麗器會(huì)話文件共享具有更好(hǎo)的性能(né會校ng)。總體上來說(shuō),當訪問量劇增的時(sh吃長í)候,如果使用數據庫保存會(huì)話帶來的問題是線性增長(ch拍章áng)的,那麼(me)使用會(huì)話文件帶來的問題幾那聽乎是爆炸性的。好(hǎo)吧,換一個更直白的說(shuō)法吧:如果話綠您的應用用戶量不大,其實讓PHP自己處理去體session就(jiù)好(hǎo)了個慢,沒(méi)必要考慮MySQL。
具體思路如下:
1、使用MySQL保存ses這亮sion,需要保存三個關鍵性的數據:session id、ses紙這sion數據、session生命期。
2、考慮到session的秒鐘使用方式,沒(méi)必要使用InnoDB引擎,MyISAM引擎可以獲海你得更好(hǎo)的性能(néng)。如果環境睡們允許,可以嘗試使用MEMORY引擎。
3、保存s街去ession數據的列,有需要的話,可以使用utf8或utf8mb4字符集;保筆是存session id的列則沒(méi)有必要,一般情況使用as慢亮cii字符集就(jiù)可以了,可以節約存儲成(chéng)本。
4、保存sessio這樹n生命期的列,可以根據工程需要進(jìn)行設計。比如datetim但訊e類型、timestamp類型、int類型。對(duì)于區區datetime、int類型可以保存sessio事會n生成(chéng)時(shí)間或過(guò)大短期時(shí)間。
5白廠、如果有必要可以擴展sessio從員n表的列并修改讀、寫函數以支持(維護)相關列來保存諸如用戶名等信息。不是
6、當前版本,隻要通過(guò)道小session_set_save_handler注冊自定義的會(huì畫懂)話維護函數就(jiù)可以,不需要在南現其之前使用session_module_name(黃新9;user')函數。
7、當read函數獲取數據并返回,樂道PHP會(huì)自動對(duì)其進(jìn)行反序列化,一般情況請不刀也要對(duì)數據進(jìn)行更改。
8、PHP傳遞給write微民函數的date參數是序列化之後(爸雨hòu)的session數據,直接保存即可,一般情況請不要對(du冷腦ì)數據進(jìn)行更改。
9、按照本段代碼通生的邏輯,PHP配置選項關于會(huì)話生命期的設資玩置已經(jīng)不再有效,這(zhè)個值可以科花自行維護,不一定需要通過(guò)get_cfg_var新線獲取。
10、s業服essionMysqlId()月時函數是爲了避免大用戶量、多台Web服務這校器情況下的碰撞,一般情況PHP自動生成(chéng)的ses站快sion id是可以滿足用戶要求的。
創建數據表代碼如下:
CREATE TABLE `sess飛可ion` (
`skey` char(32) CHARAC做體TER SET ascii N區分OT NULL,
`data` text COLLATE utf8mb4_b說們in,
`expire` int開化(11) NOT NULL,
PRIMARY KE也城Y (`skey`),
KEY `index靜下_session_expire` (`exp店睡ire`) USING BTREE
) ENGINE=MyISAM DEFAUL兒熱T CHARSET=utf8mb4 COLLATE=utf8mb4_bin問服;
PHP代碼如下:
1 <?php
2 /*
3 * 連接數據庫所需的DNS、用戶名、密碼等術湖,一般情況不會(huì)在代碼中進(jìn)行更改,
4 * 所以線志使用常量的形式,可以避免在函數中引用而需要global。
5 */
6 define作時('SESSION_DNS門務', 'mysql:h開們ost=localhost;dbname=db;cha什畫rset=utf8mb4');
7 define('SESSION_USR公明', 'usr');
8 define('SESSI器玩ON_PWD', 'pwd'雜務);
9 define('S線分ESSION_MAXLIFETIME校大39;, get_cfg_var('ses信開sion.gc_maxlifet算舊ime'));
10
11 //創建PDO連接
12 //持久化連接可以提供更好(hǎo)的效率
13 functio行了n getConnection() {
14 &nbs木朋p; try {
15 $南小conn = new PDO(SESSION_DNS, SESSI空如ON_USR, SESSION_PWD, ar船公ray(
16 &nbs算請p; PDO::ATTR_PERSISTENT =錢可> TRUE,
17 &nb月生sp; 一理 PDO::ATTR_ER亮工RMODE => PDO::ER通拿RMODE_EXCEPTION,
18 飛光 PDO::土化ATTR_EMULATE_PREPARES => FALS間理E
19 &n少店bsp; ));
20 re冷西turn $conn;
21 } catch (E筆對xception $ex) {熱站
22
23 }
24 }
25
26 //自定義的sess多相ion的open函數
27 function session頻睡MysqlOpen($savePath, $sessionName) {
28 retur問計n TRUE;
29 }
30
31 //自定義的session的close函數店件
32 functi土弟on sessionMysqlClose(報路) {
33 retur妹木n TRUE;
34 }
35 /*
36 * 由于一般不會(huì)把用戶提交的數據直接能高保存到session,所以普通情況不存在注入問題。
37 * 且處理sessio和子n數據的SQL語句也不會(huì)多次使用。因此預處理功能(唱請néng)的效益無法體現。
38 制報* 所以,實際工程中可以不必教條的使用預處理功能(子照néng)。
39 */
40 /*
41 * sessionM舞慢ysqlRead()函數中,首先化現通過(guò)SELECT count(*)友慢來判斷sessionID是否存在。
42 * 由于MySQL數據庫提供SELECT對(d區綠uì)PDOStatement::rowCount()的支持,
43 * 因此,實際的現從工程中可以直接使用rowCount()錯道進(jìn)行判斷。
44 照都*/
45 //自定義的sessi車裡on的read函數
46 //SQL語句中增加了“expire年這 > time()”判斷,用以避免讀取過(guò動通)期的session。
47 function sessionMysqlRead($se好資ssionId) {
48 try大有 {
49 &nbs場男p; $dbh = ge姐相tConnection();
50 美那$time = time();
51 &新計nbsp;
52 &nbs外畫p; $sql = 'SEL子朋ECT count(*) AS `count` FROM session 大會'
53 土信 &nbs姐錢p; . 'WHERE skey = ?村子 and expire > ?';綠紅
54 &nbs村你p; $stmt = $dbh->prepa理妹re($sql);
55 &n到明bsp; $s小美tmt->execute(array($sessionId, $time海能));
56 快紙 $data = $stmt->fetch(PD藍自O::FETCH_ASSOC);
57 i好的f ($data['co關你unt'] = 0) {
58 坐購 歌筆 return '';
59 事得 }
60 &n醫子bsp;
61 匠技 $sql = 'SELECT 多請`data` FROM `session` '
62 &nbs吃學p; 嗎男 . 'WHERE `skey` = ? and `expir金草e` > ?';
63 &n是吃bsp; $stmt =國腦 $dbh->prepare($sql);
64 &nbs南花p; $stmt->e訊舞xecute(array($sessionId, $time));
65 答唱$data = $stmt->現少fetch(PDO::FETCH_ASSOC舊河);
66 &nbs對術p; return $data['data'錢用];
67 } catch (窗行Exception $e) {
68 &nbs遠個p; return '';
69 &nb湖不sp; }
70 }
71
72 //自定義的session的火文write函數
73 //expire字段存儲的數據爲當前時(s媽技hí)間 session生命期,當這(zhè)個值離在小于time()時(shí)表明session失效。
74 function sessionMysql師計Write($sessionId, $data) {
75 &n雜章bsp; try {
76 &媽物nbsp; $dbh = get姐雨Connection();
77 &nb聽中sp; $expire = tim樹跳e() SESS照雪ION_MAXLIFETIME;
78
79 風理 $sql = 'INSERT INTO土視 `session` (`skey你學`, `data`, `expire`) '
80 &船制nbsp; &nb道兵sp;  不友; . 'values (?, ?, ?) '快窗;
81 &森森nbsp; &nb和拿sp; . 'ON DUPLICATE KEY U她們PDATE data = ?, expire = ?';
82 習玩 $stmt = $dbh-&通微gt;prepare($sql);
83 $s謝船tmt->execute(a長視rray($sessionId, $data, $expire, $data,資朋 $expire));
84 } catch (Excepti雨這on $e) {
85 &nb窗愛sp; echo $e-報的>getMessage();
86 筆冷}
87 }
88
89 //自定義的session的destroy函數
90 function session開訊MysqlDestroy($sessionId) {
91 try {
92 &nbs金區p; $dbh = getConnection()畫司;
93
94 體行$sql = 'DELETE FROM `sessi相年on` where skey = ?了體9;;
95 她上 $stmt = $dbh->pr科線epare($sql);
96 &n腦小bsp; $stmt->可放execute(array($sess相森ionId));
97 著船 return TRUE;
98 } catch (Exce吃腦ption $e) {
99 服兵 影刀 return FALSE;
100 事綠 }
101 }
102
103 //自定義的sessi鄉金on的gc函數
104 function sessionMysqlGc($lifeti都什me) {
105 try {
106 &nbs人分p; $dbh = getCon身慢nection();
107
108 $師大sql = 'DELETE FROM `session` WHER輛熱E expire < ?';
109 &師討nbsp; $stmt = $dbh->prepare那年($sql);
110 $月知stmt->execute(array(time()));
111 $dbh聽微 = NULL;
112 有土 return TRUE;
113 } catch (Excepti輛日on $e) {
114 &nb懂海sp; return FALSE;
115 }
116 }
117
118 //自定義的session的session id設置函數
119 /*
120 * 由于在session_start()之前,S玩輛ID和session_id()均無效,
121 * 故使用$_GET[session和工_name()]和$_COOK商家IE[session_name()]進(jìn)行檢測。
122 * 如果此兩(liǎng)者均爲空,則媽機表明session尚未建立,需要爲化話新session設置session id。
123 * 通過(guò)MySQL數據庫獲取uuid作科筆爲session id可以更好(hǎo)的避免session房照 id碰撞。
124 */
125 function sessionMysqlId() {
126 if (filter_inpu月放t(INPUT_GET, session_name()) =技訊= '' and
127  子畫; 嗎師 filter_input(INPUT_COOKIE,理森 session_name()) == '') {
128 答白try {
129 件雨 $dbh = getConnection快外();
130 &票那nbsp; $s購草tmt = $dbh->窗理query('SELEC志熱T uuid() AS uuid就長9;);
131 喝器 &nb如西sp; $data = $stmt->fetch(PDO身兵::FETCH_ASSOC);
132  在區; $data = str_repla飛站ce('-', '', $data[東道9;uuid']);
133 &n白關bsp; 年近 session_id($data);
134 &nbs近那p; return TRUE;
135 &nb來匠sp; } catch (Exception $ex) {
136  行煙; &城木nbsp; retu開北rn FALSE;
137 }
138 &n都習bsp;
139 }
140 }
141
142 //session啓動函數,包括了sessio哥也n_start()及其之前的所有步驟。
143 function st姐還artSession() {
144 河能 session_set_save_handler(
145  內光; 和刀9;sessionMysqlOpen',
146 &場站nbsp; '市高;sessionMysqlClo明一se',
147  家兵; 'sessio高友nMysqlRead',
148 &nb雨厭sp; 'sessionMysq是媽lWrite',
149 厭白 南喝 'sessionMysq腦章lDestroy',
150 &nbs哥去p; 'sessionMys個新qlGc');
151 科熱register_shutdown_function(照木'session_write_close聽時9;);
152 sessionMysqlId();
153 session_start喝物();
154 }
在建站的時(shí)候,都(dōu)會(huì)采用單一入口(多見爲從服子index1.html)的形式,我覺得,單一入口得醫的好(hǎo)處有下面(miàn)兩(liǎng)點: 信村 1.後(hòu)面(mi火新àn)的程序可以統一處理,比如村校說(shuō)要開(kāi)發(fā)時(sh很音í)候用到某個第三方類庫,隻需要在入口文件引入,其餘的程序都(dōu)會(說姐huì)可以引用 2.路徑可以統一處理。因白銀爲都(dōu)是從index1.html開(kāi)始,所以引入文件隻要學短相對(duì)于index1.html的路徑即亮訊可。