问题
请注意,下面直接使用 Eugen 的观点解决了这个问题!
我正在为一个 PHP/MySQL 用户驱动的站点编写一个聊天模块,允许两个用户交 friend ,并选择了 eJabberd 作为聊天系统。
我已经使用 PHP 守护程序成功设置了外部身份验证,现在我已经成功地通过使用 mod_roster_odbc
并填充 MySQL rosterusers将友谊加入了 eJabberd
表手动。经过大量挖掘,我设法找到了 this particular comment非常有助于了解将每一列设置为什么,以便在聊天模块的 friend 列表中表示该友谊。
我目前处理友谊的方法是在 rosterusers
表中插入两行:
# Relationship user1 => user2
INSERT INTO rosterusers (username, jid, subscription, ask, server, type)
VALUES ('user1', 'user2@myserver.org', 'B', 'N', 'B', 'item');
# Relationship user2 => user1
INSERT INTO rosterusers (username, jid, subscription, ask, server, type)
VALUES ('user2', 'user1@myserver.org', 'B', 'N', 'B', 'item');
我对此不太满意,因为互惠友谊需要两行。
我了解 XMPP 按照标准允许用户之间的单链接和双链接。正如我的问题的性质所推断的那样,我自己的应用程序的 friend 系统使用一行来表示友谊。
我的主要问题:
- 是否可以将这种友谊巩固为一行?我尝试了这个 unofficial documentation 的一些组合但还没有成功。我正在通过使用 Pidgin 客户端连接到我的 XMPP 服务器进行测试。
- 保持两个数据库( friend 和 XMPP 名册)同步的最佳方法是什么?我认为 MySQL
TRIGGER
可能是目前最干净的选择。
如果不是,那么我的另一个选择是更改 rosterusers
表并让它引用我自己的应用程序的 friend 行,以便它像跨数据库外键一样工作。
解决方案代码
我按照 Eugen 的建议创建了一个 View 。代码不是最优雅的,但我已经对其进行了测试,它可以在 MySQL 5.5 上与 eJabberd 2.1 一起使用。
我的确切设置使用两个数据库,因此我通过使用 main_database.table_name
显式引用我的主应用程序的数据库。
该代码是两个查询的联合体 - 第一个获取 User、Friend,然后第二个插入 Friend、User。我正在使用 UNION ALL
来提高速度,并让“重复项”通过。
我认为这是一种非常好的处理问题的方法,因为不需要更改应用程序,而且它会立即更新。
CREATE VIEW rosterusers AS
SELECT LCASE(ua1.Username) AS `username`, CONCAT(LCASE(ua2.Username), '@myserver.org') AS `jid`,
'B' AS `subscription`,
'N' AS `ask`,
'N' AS `server`,
'item' AS `type`,
'B' AS `subscribe`,
d1.Created AS `created_at`,
ua2.Username AS `nick`,
'' AS `askmessage`
FROM main_database.User_Friend AS `d1`
INNER JOIN main_database.User AS `ua1` ON `d1`.UserID = `ua1`.ID
INNER JOIN main_database.User AS `ua2` ON `d1`.FriendID = `ua2`.ID
WHERE d1.IsApproved = 1
UNION ALL
SELECT LCASE(ub2.Username) AS `username`, CONCAT(LCASE(ub1.Username), '@myserver.org') AS `jid`,
'B' AS `subscription`,
'N' AS `ask`,
'N' AS `server`,
'item' AS `type`,
'B' AS `subscribe`,
d2.Created AS `created_at`,
ub1.Username AS `nick`,
'' AS `askmessage`
FROM main_database.User_Friend AS `d2`
INNER JOIN main_database.User AS `ub1` ON `d2`.UserID = `ub1`.ID
INNER JOIN main_database.User AS `ub2` ON `d2`.FriendID = `ub2`.ID
WHERE d2.IsApproved = 1;
最佳答案
IIUC,rosterusers
表在您的 eJabberd
服务器应用程序的 POV 中是只读的。这将使它变得简单,用 view
替换它,在您自己的 friends 表中创建所需的 1 行中的 2 行。
不知道你自己的friendship表的结构,没法给你完整的代码,这里是我想的伪SQL
CREATE VIEW rosterusers AS SELECT * FROM (
SELECT
selfuser.name AS username,
frienduser.jid AS jid,
-- ....,
selfuser.jid AS jid_as_id
FROM
users AS selfuser
INNER JOIN friendships ON ....
INNER JOIN users AS frienduser ON ...
UNION SELECT
frienduser.name AS username,
selfuser.jid AS jid,
-- ....,
frienduser.jid AS jid_as_id
FROM
users AS selfuser
INNER JOIN friendships ON ....
INNER JOIN users AS frienduser ON ...
);
然后
SELECT
username, jid, subscription, ask, server, type
FROM rosterusers
WHERE jid_as_id='user1@myserver.org'
应该给你 2 行,一个来自 View 中 UNION
的每个部分
关于mysql - 使用 MySQL 和 ejabberd 进行高效的外部排类,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11360759/