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 语句应该是什么样的?

也许我让这比我需要的更复杂。任何帮助是极大的赞赏!

4

6 回答 6

1

由于两个用户几乎同时发布两条消息的可能性,您不应依赖于两个 ID 的自动增量。如果第一个脚本将数据插入表中,那么第二个脚本在第一个脚本完成插入之前tbl_pm设法执行其tbl_pm和插入,第一个脚本的两个数据库插入将具有不同的 ID。tblpm_infotblpm_info

除此之外,您的数据库结构似乎没有很好地组织手头的任务。假设您的消息可能很长,并且发送给大量用户,那么将消息内容存储一次是理想的,并且对于每个收件人都有未读状态、已读时间等。例如:

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'data' 表中不存在的,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')" );
 }
于 2009-07-24T22:04:20.187 回答
1

1)绝对是的,除非您提供唯一的主键的不同方式,否则 id 应该自动递增。mysql_insert_id()您可以直接使用 mysql或从 mysql获取插入的 id LAST_INSERT_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)");

(复制消息等,仅接收者更改)

或者

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 列表并再次用逗号包装(稍后我将详细说明原因)。

因此,您必须再次将接收者的 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, //多用户消息

为您使用的 ID 为 $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 并一次性更新“收件人”字段

"UPDATE table SET readers=CONCAT(',',TRIM(TRAILING ',' FROM readers),',$user_id,') WHERE id IN (".implode(',' ,$received_msg_ids).")"
于 2009-07-27T14:44:05.230 回答
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 它将为您完成所有的魔法。

于 2009-07-23T17:19:55.297 回答
0

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

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

于 2009-07-24T09:33:40.407 回答
0

就您个人而言(假设示例未简化并且我看不到更多示例),我会将这两个表中的数据存储在一个表中,因为它们似乎直接相关:

tbl_pm tbl:

message_id

发送日期

标题

内容

状态枚举('未读','已读')默认'未读'

发件人ID

接收者 ID

所以你最终得到了像上面这样的东西,真的不需要加入,因为关系总是一对一的?您在 tbl_pm 表中已读/未读,这肯定会因每个收件人而更改,这意味着您无论如何都必须为每个收件人存储邮件的副本。也许状态应该在 tbl_pm 信息表中。

如果您确实想插入两个表,请尝试在查询中使用 last_insert_id() 或 mysql_insert_id() ,如上所述,从 php.ini 中。

于 2009-07-24T15:39:44.507 回答
0

我可能会做类似于 gavin 推荐的事情,但如果您想要线程消息,则必须添加另一个键,如下所示:

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

然后,您可以在没有单独的表或系统的情况下嵌套消息。

于 2009-07-24T15:48:16.020 回答