我目前正在创建一个私人消息系统(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语句应该是什么样的?
也许我正在使这比我需要的更复杂。非常感谢任何帮助!
答案 0 :(得分:1)
由于两个用户几乎可能同时发布两条消息,因此您不应该依赖两个ID的自动增量。如果第一个脚本将数据插入tbl_pm
表,则第二个脚本会在第一个脚本完成其tbl_pm
插入之前设法执行其tblpm_info
和tblpm_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)
然后你可以拥有没有单独的表或系统的嵌套消息。