【问题标题】:How can I keep two different columns in sync from two different tables?如何使两个不同表中的两个不同列保持同步?
【发布时间】:2018-04-17 01:32:22
【问题描述】:

我有一个users 表,我有一个oauth 表。 oauth 表包含三列:

  • user_id
  • oauth_id
  • oauth_provider

oauth 表的目的是将提供者 ID 链接到内部用户 ID,并为每个用户提供唯一标识符。 我试图让自己进入一种情况,我可以将usersid 列与oauthuser_id 同步。 我试过的东西:

node 环境,node-postgres 作为 DB 客户端。

export default function addUser(user: UserDetails) {
  const { displayName, phoneNumber, isDriver, oauthId, oauthProvider } = user;
  let query;
  query = {
    text:
      'INSERT INTO users(display_name, phone_number, is_driver) VALUES ($1, $2, $3);',
    values: [displayName, phoneNumber, isDriver]
  };
  executeQuery(query);
  query = {
    text:                                                           // Something Else?
      'INSERT INTO oauth(user_id, oauth_id, oauth_provider) VALUES ((select max(id) from users), $1, $2);',
    values: [oauthId, oauthProvider]
  };
  executeQuery(query);
}

这是有风险的,如果同时完成两个请求,这将不起作用。 处理这种情况的方法是什么?谢谢。

编辑

我想我找到了解决方案,这是线程安全的吗?

export default async function addUser(user: UserDetails) {
  const { displayName, phoneNumber, isDriver, oauthId, oauthProvider } = user;
  let query;
  query = {
    text:
      'INSERT INTO users(display_name, phone_number, is_driver) VALUES ($1, $2, $3) RETURNING id;',
    values: [displayName, phoneNumber, isDriver]
  };
  const result = await executeQuery(query);

  if (result)
    query = {
      text:
        'INSERT INTO oauth(user_id, oauth_id, oauth_provider) VALUES ($1, $2, $3);',
      values: [result[0].id, oauthId, oauthProvider]
    };
  executeQuery(query);
}

【问题讨论】:

  • 我觉得不错。更进一步,我会为此使用 Sequelize,因为我相信您正在重新发明轮子。

标签: node.js postgresql database-design


【解决方案1】:

你能绝对保证这个函数是现在和将来将新记录写入用户表的唯一方法吗?是的,我没想到。

您为什么不想创建一种方法来保证写入用户表的任何记录,无论是从应用程序中的任何位置或任何未来应用程序或任何未来应用程序或任何数据库开发人员或 DBA 运行的任何脚本中的任何其他函数,都将还要为Oauth表生成对应的记录吗?

为此,只需在用户表上创建一个after insert 触发器,将正确的行插入到 Oauth 表中。然后,无论如何创建新用户,都会创建匹配的 auth 条目。

从应用程序的角度来看,还有一个额外的好处是,两个插入都成为同一事务的一部分。因此,向任一表写入行的任何问题都会产生一个异常和一个回滚,这意味着不会对任一表进行任何更改。这大大简化了错误处理。

在执行此操作时,创建一个before delete 触发器,以便在删除用户时删除相应的 Oauth 条目。相同的好处。

那么您就不必担心 Oauth 表与 Users 表保持同步。 (对于不同程度的never,就是这样。但它会非常接近。)

一般经验法则:在尽可能低的级别执行必要的操作。应用代码和存储过程是高级别的,触发器、检查约束和域定义是低级的。

【讨论】:

  • oauth中的user_id不应该是usersid的外键吗?
  • 看起来确实像。为什么?
【解决方案2】:

作为您提出的解决方案的替代方案,您可以使用 CTE 在单个 SQL 语句中执行两个插入操作:

WITH userinsert AS (
    INSERT INTO users(display_name, phone_number, is_driver) 
       VALUES ($1, $2, $3) RETURNING id
)
INSERT INTO oauth(user_id, oauth_id, oauth_provider) 
    VALUES ((SELECT id FROM userinsert), $4, $5);

【讨论】:

  • 谢谢,我不知道WITH 关键字。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-02-13
  • 1970-01-01
  • 2011-12-01
  • 2021-06-21
  • 2017-07-04
  • 1970-01-01
相关资源
最近更新 更多