创建触发器以更新另一个服务器数据库上的表数据

mkb*_*mkb 9 mysql trigger

我正在 MySQL 中创建一个触发器,我需要一些帮助。

我在 2 个不同的 Web 服务器 S1 和 S2 上有 2 个网站、2 个数据库(同名)。

这些数据库具有相同的表名。

我希望两个网站上的用户数据都相同。

因此,如果一个用户在 S1 上注册,那么该用户注册信息应该传递给 S2。

如果在 S1 上更新了用户注册信息,则应在 S2 上更新相同的信息。

这同样适用于 S2。

如何创建触发器,以便每次在 S1 上的数据库中进行插入/更新/删除时,S2 上的用户表也会自动更新。

并且每次在 S2 上的数据库中进行插入/更新/删除操作时,S1 上的用户表也会自动更新。

这可能吗?你能提供一些例子吗?

Mic*_*bot 12

为了完成您想要做的事情,可以将两台服务器上的FEDERATED存储引擎与触发器结合使用,以允许每台服务器更新另一台服务器的数据库。

这并不完全是一个简单的开箱即用解决方案,因为它需要额外的预防措施,并要求您决定一致性还是隔离容忍度更重要,并允许查询在其他服务器不可用时失败(更多一致性) 或使用 aCONTINUE HANDLER来抑制错误(隔离容差)。

但这里有一个极其简化的例子。

每个服务器将具有相同的配置。

本地用户表:

CREATE TABLE user (
  username varchar(64) NOT NULL,
  password varbinary(48) NOT NULL, /* encrypted of course */
  PRIMARY KEY(username)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
Run Code Online (Sandbox Code Playgroud)

联合到另一台服务器上的用户表的本地表。

CREATE TABLE remote_user (
  username varchar(64) NOT NULL,
  password varbinary(48) NOT NULL, /* encrypted of course */
  PRIMARY KEY(username)
) ENGINE=FEDERATED DEFAULT CHARSET=utf8 CONNECTION='mysql://username:pass@the_other_host:port/schema/user';
Run Code Online (Sandbox Code Playgroud)

从一台服务器上的 remote_user 中选择将从另一台服务器检索记录,并在该表上插入/更新/删除将更改另一台服务器上的数据。

所以,我们创建触发器确实达到了更新远程服务器的目的。它们被写成BEFORE触发器,其想法是我们不想对自己做一些我们不能对另一台服务器做的事情——例如,如果一个用户名已经存在于另一台服务器上,但不在这里,我们希望另一台服务器上的插入抛出一个错误,阻止我们在此处创建用户......而不是在此处创建一个用户名冲突的用户。当然,这是您需要做出的权衡决定之一。

DELIMITER $$

CREATE TRIGGER user_bi BEFORE INSERT ON user FOR EACH ROW
BEGIN
  INSERT INTO remote_user (username,password) VALUES (NEW.username,NEW.password);
END $$

CREATE TRIGGER user_bu BEFORE UPDATE ON user FOR EACH ROW
BEGIN
  UPDATE remote_user 
     SET username = NEW.username,
         password = NEW.password
   WHERE username = OLD.username;
END $$

CREATE TRIGGER user_bd BEFORE DELETE ON user FOR EACH ROW
BEGIN
  DELETE FROM remote_user
   WHERE username = OLD.username;
END $$

DELIMITER ;
Run Code Online (Sandbox Code Playgroud)

这不是一个完美的解决方案,也不是一个高可用性的解决方案,因为它依赖于两个系统之间的可靠连接,即使您使用的是 InnoDB 和事务,您对目标表采取的操作也不是本地事务的一部分并且无法回滚。

我经常使用FEDERATED引擎;它在我的环境中用于许多创造性目的,包括一种情况,我使用触发器启动的联合查询对外部数据源施加外键约束;但是,我将其用于后端流程,在这些流程中,超时、编码错误或服务器到服务器网络/中断/隔离事件等意外问题不会导致我们网站上的最终用户遇到任何类型的问题. 您容忍这种情况的能力将是决定这是否是合适解决方案的主要决定因素。

另一种方法是在主/主复制中配置您的两台服务器。为此,您需要在每台服务器上使用不同的数据库名称,以便对于大多数复制的事件,两台服务器不可能相互冲突。在最坏的情况下,如果您失去连接或遇到复制错误,两个站点仍将独立运行,您可以重新同步和恢复。配置看起来像这样:

database_a database for site A
database_b database for site B
database_c database for only the shared table(s)
Run Code Online (Sandbox Code Playgroud)

然后,在 database_a 和 database_b 中:

CREATE ALGORITHM=MERGE SQL SECURITY INVOKER VIEW user AS SELECT * FROM c.user;
Run Code Online (Sandbox Code Playgroud)

MySQL 会将 database_a.user 和 database_b.user 视为“真实”用户表 database_c.user 的别名,因此除了使用其指定的数据库外,您不必更改应用程序(即,您不必配置它可以理解用户表实际上处于不同的模式中,因为使用此配置视图将非常透明地运行)。如果模式具有针对用户表的外键,您将针对真正的基表 database_c.user 声明这些外键。

配置两台服务器以复制所有内容,但如果您的表使用自动增量,则设置auto_increment_incrementauto_increment_offset适当地使共享表上的自动增量值不会发生冲突。(请注意,文档说这些变量仅适用于NDB表格,但这并不准确)。

此设置的一个额外优势是,您的两台服务器将拥有另一个站点数据的完整副本,您可能会利用这些数据从其中一台服务器的硬件故障中恢复。


32b*_*oat 1

这只是众多表中的一张,应该是相等的,不是吗?

因此,触发器将不起作用,因为它们只能在同一服务器上的同一架构中执行。

我猜你有3个选择:

  1. 手动同步,例如通过调用一个脚本来执行对其他服务器上的 S1 上的用户数据执行的所有查询。有点丑。

  2. 将此表上的所有查询定向到一台服务器,例如 S1 包含用户表,而您的应用程序(无论它是什么)在服务器 2 上不会查询 S2 上的本地用户表,而是远程查询 S1 上的用户表。没那么好。

  3. 使用 FEDERATED 引擎。将用户数据存储在S1上,在S2上创建与FEDERATED相同的表结构。这意味着,S2 不保存物理用户数据,而是保存到 S1 上的表的连接。S2 上执行的所有操作均在 S1 上完成。请参阅http://en.wikipedia.org/wiki/MySQL_Federatedhttp://dev.mysql.com/doc/refman/5.0/en/federated-storage-engine.html以了解这是否适合您的需求。

在所有 3 种情况下,很难给出有关同步之间延迟的说明。选项 3 是唯一一个您只需要调整数据库而不是应用程序的选项,但我真的不知道这是否是一个大问题。