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)."' "
如果您需要更类似于会议或论坛的方法,并且需要跟踪谁阅读了该消息,您可能需要跟踪所有相关用户。
假设在一次“多用户会议”中不会有 100 多人,我会使用一张表来发送消息,并使用“逗号分隔和包装列表”技巧来存储标签。
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)
recipients/readers 字段的秘诀是填充它们以逗号分隔的 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, ' 可能会给您带来误报,例如'234,56','1**,234','9,452,**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).")"