具有线程/回复的私人消息系统

时间:2009-07-23 17:03:50

标签: php mysql insert-id

我目前正在创建一个私人消息系统(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语句应该是什么样的?

也许我正在使这比我需要的更复杂。非常感谢任何帮助!

6 个答案:

答案 0 :(得分:1)

由于两个用户几乎可能同时发布两条消息,因此您不应该依赖两个ID的自动增量。如果第一个脚本将数据插入tbl_pm表,则第二个脚本会在第一个脚本完成其tbl_pm插入之前设法执行其tblpm_infotblpm_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'值设置为自动递增,但'info'表还有一个pm_id字段,用于保存'数据的ID号它引用的行,这样您就可以确定每行在“信息”表中都有一个主键,您可以使用该主键进行选择。

如果您想使用MySQL设置真正的关系数据库,请确保您的引擎设置为InnoDB,这允许在表之间设置关系,因此(例如)如果您尝试在“info”表中插入某些内容指的是“数据”表中不存在的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')" );
 }

答案 1 :(得分:1)

1)定义是,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中;也影响你是否真的需要“读取”字段)。

“私聊”方法是最简单的方法,然后你最好将消息存储在一个表中,将from-to关系存储到另一个表中(并在其上使用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)");

(复制邮件等,只有收件人更改)

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)."' "

如果您需要更多类似于会议或论坛的方法,并且需要跟踪谁阅读了该消息,您可能需要跟踪所涉及的所有用户。

假设在一个“多用户会议”中不会有一百多人,我会使用一个表来获取消息,并使用“逗号分隔和包装列表”技巧来存储标签。< / p>

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列表并再次用逗号包装(稍后我会深入了解原因)。

所以你必须再次将接收者的id收集到一个数组中,例如$ recepients = array(2,3,5)并修改你的插入内容:

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

你得到的表格就像
一样 ...发件人|受助
...... 1 | ,2,//单个用户消息
...... 1 | ,3,5,//多用户消息

为身份为$ user_id = 2的用户选择所有消息,然后选择

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

之前我们包含了内容的内容列表,例如: '5,2,3'成为',5,2,3',INSTR在这里告诉',2,'是否作为子串包含在某处 - 因为只搜索'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}

导致:

...发件人|收件人|读者
...... 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

从结果中收集消息ID并一次性更新“recepients”字段

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

答案 2 :(得分: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,它将为你做所有的魔术。

答案 3 :(得分:0)

在普通的PHP / Mysql调用中,mysql_insert_id()返回先前INSERT操作中的自动递增值

因此,您插入消息,收集新生成的ID,并将该值放入另一个表中。

答案 4 :(得分:0)

就你个人而言(假设示例没有简化,我看不到更多)我会将这两个表中的数据存储在一个表中,因为它们看起来直接相关:

tbl_pm tbl:

MESSAGE_ID

DATE_SENT

标题

含量

状态ENUM('未读','读')DEFAULT'未读'

SENDER_ID

receiver_id

所以你最终得到了类似上面的内容,因为关系总是1比1,所以实际上不需要加入?您已经在tbl_pm表中读取/未读取,每个收件人肯定会更改,这意味着您无论如何都必须为每个收件人存储邮件的副本。也许staus应该在tbl_pm信息表中。

如果你想插入两个表,请尝试在查询中使用last_insert_id()或 mysql_insert_id()如上所述,来自php。

答案 5 :(得分:0)

我可能会做一些类似于gavin推荐的内容,但是如果你想要线程消息,你必须添加另一个密钥,如下所示:

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

然后你可以拥有没有单独的表或系统的嵌套消息。