2009-07-23 92 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')"); 
}