2009-07-23 88 views
1

我目前正在創建一個私人消息系統(PHP/MySQL),用戶可以一次向多個收件人發送消息,然後這些用戶可以決定回覆。帶線程的私人消息系統/回覆

這裏就是我目前正在工作:

tbl_pm tbl: 
id 
date_sent 
title 
content 
status ENUM ('unread', 'read') DEFAULT 'unread' 

tblpm_info tbl: 
id 
message_id 
sender_id 
receiver_id 

不過,我需要一些幫助確定兩件事情的邏輯:

1)當創建一個新的消息,應「ID 「是自動增量?如果兩個表中的「id」列設置爲自動遞增,我將如何設置「關係表」中的「message_id」列?

例如,創建一個新的消息時,我的MySQL聲明如下:

<?php 
mysql_query("INSERT INTO `tblpm` (title, content, sender_id, date_sent) VALUES ('$subject', '$message', '$sender', NOW())"); 

在同一聲明中,我將如何進入tblpm的「自動遞增」值入tblpm_info「 message_id「字段?

2)當用戶回覆郵件時,我的MySQL語句應該是什麼樣的?

也許我正在使這個比我需要更復雜。任何幫助是極大的讚賞!

回答

1

1)Definetely是,ID的應該是自動自動遞增,除非你提供一個主鍵的不同手段這是獨一無二的。你得到的插入或者與從MySQL直接mysql_insert_id()LAST_INSERT_ID()的ID,所以要張貼一些連接的信息,你可以做任何

mysql_query("INSERT INTO table1 ...") 
    $foreign_key=mysql_insert_id(); //this gives you the last auto-increment for YOUR connection 

或者,但只有當你絕對肯定沒有其他人寫入表在平均時間或有過交易的控制,插入後做:

$foreign_key=mysql_query("SELECT LAST_INSERT_ID()") 
INSERT INTO table2 message_id=$foreign_key 

,或者不拉FK到PHP,都在同一個交易(我也建議包裹SQL作爲交易太)的東西如:

"INSERT INTO table1...; INSERT INTO table2 (message_id,...) VALUES(LAST_INSERT_ID(),...)" 

根據您的語言和mysql庫,您可能無法發出多重查詢方法,因此您最好使用第一種方法。

2)這可以有很多方法,取決於你是否也需要回復所有接收者(例如會議),以線程/類似論壇的方式答覆,客戶端是否可以存儲上次檢索消息/ ID(例如,在cookie中;也影響你是否真的需要「讀」字段)。

「私人聊天」方法是最簡單的方法,那麼您可能更好的方法是將消息存儲在一個表中,並將來自到的關係存儲到另一個表中(或使用JOIN),或者只是重新填充在一個表中的消息(因爲現在存儲便宜)。因此,簡單的模型是一個表:

table: message_body,from,to 
$recepients=array(1,2,3..); 
foreach($recepients as $recepient) 
mysql_query("INSERT INTO table (...,message_body,from,to) VALUES(...,$from,$recepient)"); 

(複製消息等,只有recepient變化)

message_table: id,when,message_body 
to-from-table: id,msg_id,from,to 

$recepients=array(1,2,3,...); 
mysql_insert("INSERT INTO message_table (when,message_body) VALUES(NOW(),$body)"); 
$msg_id=mysql_insert_id(); 
foreach($recepients as $recepient) 
mysql_query("INSERT INTO to-from-table (msg_id,from,to) VALUES($msg_id,$from,$recepient)"); 

(消息中插入一次,存儲關係和FK對於所有收信人)

然後每個客戶端存儲他/她接收到的最後一個message_id(默認爲0),並且假設所有先前的消息已經被讀取):

"SELECT * FROM message WHERE from=$user_id OR to=$user_id WHERE $msg_id>$last_msg_id" 

,或者我們只需要注意最後的輸入時間從用戶和然後查詢任何新的消息:

"SELECT * FROM message WHERE from=$user_id OR to=$user_id WHERE when>='".date('Y-m-d H:i:s',$last_input_time)."' " 

如果你需要一個更會議室套裝或論壇胎面類似的方法,並且需要跟蹤誰讀取或不讀取消息,您可能需要跟蹤所有涉及的用戶。

假設在一個「多用戶會議」中不會有數百人蔘加會議,我會用一張桌子來發送消息,並使用「逗號分隔和包裹列表」技巧,我用它來存儲標籤。

id autoincrement (again, no need for a separate message id) 
your usual: sent_at, title (if you need one), content 
sender (int) 
recepients (I'd go with varchar or shorter versions of TEXT; whereas TEXT or BLOB gives you unlimited number of users but may have impact on performance) 
readers (same as above) 

爲受助/讀者場的祕訣是填充它們以逗號分隔的ID列表,再敷在逗號(我會dulge到爲什麼後來)。

因此,您必須再次將收件人的id收集到數組中,例如, $受助=陣列(2,3,5)和修改插入:

"INSERT INTO table (sent_at,title,content,sender,recepients) VALUES(NOW(),'$title','$content',$sender_id,',".implode(',', $recepients).",')" 

你表中的行狀
...發件人| recepients
...           1 | ,2,//單用戶消息
...           1 | ,3,5,//多用戶消息

選擇具有的$ USER_ID = 2你去

SELECT * FROM table WHERE sender=$user_id OR INSTR(recepients, ',$user_id,') 

以前我們包裹受助的內爆列表中的ID,例如用戶的所有郵件'5,2,3'變成',5,2,3',並且INSTR在這裏告訴'2,'是否作爲子字符串被包含在某處 - 自從尋求'2','2'或'2' '可能會給你錯誤的肯定例如' 34,56','1 **,2 34','9,45 2,** 89'相應地 - 這就是爲什麼我們必須首先包裝清單。

當用戶讀取/接收他/她的消息,則其ID添加到讀者列表,如:

UPDATE table SET readers=CONCAT(',',TRIM(TRAILING ',' FROM readers),',$user_id,') WHERE id=${initial message_id here} 

導致:

...發件人| recepients |讀者
...           1 | ,2,              | ,2,
...           1 | ,3,5,          | ,3,5,2,

或者我們現在可以修改初始查詢添加一列「is_read」陳述用戶是否事先閱讀信息,或不:

SELECT * FROM table WHERE INSTR(recepients, ',$user_id,'),INSTR(readers, ',$user_id,') AS is_read 

收集信息的IDS結果並一次性更新「recepients」字段

"UPDATE table SET readers=CONCAT(',',TRIM(TRAILING ',' FROM readers),',$user_id,') WHERE id IN (".implode(',' ,$received_msg_ids).")" 
+0

感謝您的答覆,我還挺喜歡‘包裝清單’的把戲,不過,我有一個問題:使用這種方法,我怎樣才能跟蹤郵件實際被讀取的時間戳,換句話說,除了跟蹤「is_read」,我還想跟蹤每個收件人的「when_read」。 – Dodinas 2009-07-29 21:54:08

0

是的。你肯定會在這兩個id上設置auto_increment。

要設置message_id,您可以以編程方式將其插入到那裏。

您的查詢應該是這樣的:

mysql_query("INSERT INTO `tblpm` (title, content, sender_id, date_sent) VALUES ('$subject', '$message', '$sender', NOW())"); 

注意這是相同的!如果id設置爲auto_increment,它會爲你做所有的魔術。

+0

感謝您的回覆。你可以在你的意思是闡述「要設置MESSAGE_ID」你會編程插入它在那裏?」 感謝。 – Dodinas 2009-07-23 17:26:10

0

在純PHP/MySQL調用,mysql_insert_id()返回上一步INSERT操作

的自動遞增的值,所以,您插入郵件,收集新生成的ID,並且這個值放到其他表。

0

個人在你的情況(提供的例子不是簡化,這裏就不多,我不能看到)我想數據來自那些表存儲在一個單一的表,因爲它們出現直接相關:

tbl_pm TBL:

MESSAGE_ID

DATE_SENT

標題

內容

狀態ENUM( '未讀', '讀')DEFAULT '未讀'

SENDER_ID

receiver_id

所以,你最終的東西,如上述情況,確實沒有任何需要作爲關係的連接始終是1比1?您已在tbl_pm表中讀取/未讀取,這肯定會對每個收件人進行更改,這意味着無論如何您都必須爲每個收件人存儲郵件的副本。也許staus應該在tbl_pm信息表中。

如果您確實想要插入到兩個表中,請嘗試在查詢中使用last_insert_id()或從php內部使用mysql_insert_id(),如上所述。

到推薦
0

我可能會做同樣的事情什麼加文,但是如果你想線程的消息,你必須添加另一個關鍵,是這樣的:

private_messages 
- title (text) 
- date (timestamp) 
- content (text) 
- status (enum) 
- sender_id (int) 
- receiver_id (int) 
- parent_message_id (int) 

沒有然後,你可以有嵌套的消息單獨的桌子或系統。

1

由於兩個用戶幾乎同時發佈兩條消息的可能性,您不應該依靠兩個ID上的自動增量。如果第一個腳本將數據插入到tbl_pm表中,則第二個腳本設法在第一個腳本完成其tblpm_info插入之前執行它的tbl_pmtblpm_info插入,第一個腳本的兩個數據庫插入將具有不同的ID。

除此之外,您的數據庫結構似乎並沒有很好地組織起來。假設您的郵件可能很長,併發送給大量的用戶,那麼將郵件內容存儲一次是理想的,並且每個收件人都有未讀狀態,讀取時間等。例如:

CREATE TABLE `pm_data` (
    `id` smallint(5) unsigned NOT NULL auto_increment, 
    `date_sent` timestamp NOT NULL, 
    `title` varchar(255) 
    `sender_id` smallint(5) unsigned, 
    `parent_message_id` smallint(5) unsigned, 
    `content` text, 
    PRIMARY_KEY (`id`) 
); 
CREATE TABLE `pm_info` (
    `id` smallint(5) unsigned NOT NULL auto_increment, 
    `pm_id` smallint(5) unsigned NOT NULL, 
    `recipient_id` smallint(5) unsigned, 
    `read` tinyint(1) unsigned default 0, 
    `read_date` timestamp, 
    PRIMARY_KEY (`id`) 
); 

創建這兩個表,並注意他們都有一個'id'值設置爲自動增量,但'信息'表也有一個pm_id字段,它將保存'數據'行的ID號碼指的是,以確保每行在「信息」表中都有一個主鍵,您可以從中選擇。

如果您想要使用MySQL進行真正的關係數據庫設置,請確保您的引擎設置爲InnoDB,它允許在表之間建立關係,因此(例如)如果您嘗試在「信息」表「數據」表中不存在的引用pm_id的表,INSERT將失敗。

一旦你選擇了一個數據庫結構,那麼你的PHP代碼看起來是這樣的:

<?php 
// Store these in variables such that if they change, you don't need to edit all your queries 
$data_table = 'data_table'; 
$info_table = 'info_table'; 
mysql_query("INSERT INTO `$data_table` (title, content, sender_id, date_sent) VALUES ('$subject', '$message', '$sender', NOW())"); 
$pmid = mysql_insert_id(); // Get the inserted ID 
foreach ($recipent_list as $recipient) { 
     mysql_query("INSERT INTO `$info_table` (pm_id, recipient_id) VALUES ('$pmid', '$recipient')"); 
}