如何根据每个客户端动态连接mysql数据库?

How to dynamically connect mysql database according to each client?

我在这里使用 MEAN 堆栈构建 SaaS 产品 M = mysql

我正在使用 sequelize 作为 mysql 的 ORM,我的连接:

const sequelize = new Sequelize('smallscale_superapp', 'root', 'root1', {
  host: '127.0.0.1',
  port: 3306,
  dialect: 'mysql',
  logging: false,
});

例如,我有一个管理员超级应用程序,所以我创建了一项业务,例如业务代码名为 “001abcd”,这个业务代码存储在我的主管理数据库中,然后我告诉我所有的客户去一个名为 "example.com" 的特定 url。

因此,如果他们输入 url,主页将看起来像 slack.com 有一个输入框,硬编码后的值称为 example.com

所以现在我的客户在输入框中输入了我创建的业务代码并存储在我的主数据库中。

将业务代码放入输入框后,将打开一个名为“001abcd.example.com”的新子域(我正在检查业务代码是否与我的主数据库匹配,如果匹配我正在创建动态子域)

所以如果一切顺利,在创建子域客户端页面后将显示为登录屏幕,他们需要在其中注册并且注册详细信息需要在那里动态

注意:我在创建业务时在我的主数据库table中获取客户端数据库、用户名、主机、密码。

如何使用 sequelize mysql 完成此操作?

如何让sequelize连接根据客户端登录动态连接?

正如我之前所说,我的数据库中有客户端 dbname..etc 我正在尝试创建这样的连接:

exports.dynamicDatabase = (req, res) => {
  const { code } = req.params;
  Business.find({
    where: { code },
    raw: true,
  })
    .then((data) => {
      const sequelizeClient = new Sequelize(data.dbname, data.dbusername, data.dbpassword, {
        host: data.dbhost,
        port: 3306,
        dialect: 'mysql',
        logging: false,
      });
    })
    .catch((err) => { res.status(400).send(err.message); });
};

现在在我的这个函数之外我正在尝试同步 tables,像这样:

sequelizeClient.authenticate().then((err) => {
  if (err) {
    console.log('There is connection in ERROR.');
  } else {
    console.log('Dynamic MYSQL Connection has been established successfully');
  }
});
sequelizeClient.sync().then(() => {
  console.log('Dynamic Missing Table Created');
}, (err) => {
  console.log('An error occurred while creating the table:', err.message);
});

变量sequelizeClient在函数内部,所以我无法访问?全球。

所以我在全局创建变量,但是有一个问题

我在函数中有 sequelizeClient 变量,只有在 url、

中进入我的域后,该函数才会执行

但是 sequelizeClient.sync() 不在函数内部,所以当我启动节点 server.js 时它会抛出错误:

sequelizeClient.authenticate().then((err) => {
[0]                 ^
[0]
[0] TypeError: Cannot read property 'authenticate' of undefined

最后我尝试了这个并使它起作用,但我不知道这是不是好方法,所以请告诉我这是否是好方法?

我正在通过用户请求参数获取准确数据:

let sequelizeClient;
let Login;
exports.getDomain = (req, res) => {
  const { code } = req.params;
  Business.find({
    raw: true,
    where: { code },
  }).then((data) => {
    if (data === null) {
      res.status(400).send(data);
    } else {
      sequelizeClient = new Sequelize(data.dbname, data.dbusername, data.dbpassword, {
        host: data.dbhost,
        port: 3306,
        dialect: 'mysql',
        logging: false,
      });

      // end user connections
      sequelizeClient.authenticate().then((err) => {
        if (err) {
          console.log('There is connection in ERROR.');
        } else {
          console.log(`${data.code} MYSQL Connection has been established successfully`);
        }
      });

      sequelizeClient.sync().then(() => {
        console.log(`${data.code} Missing Table Created`);
      }, (err) => {
        console.log('An error occurred while creating the table:', err.message);
      });

      // mysql tables;
      Login = sequelizeClient.define('login', {
        username: Sequelize.STRING,
        firstName: Sequelize.STRING,
        lastName: Sequelize.STRING,
      });
    }
  });
};

我将 table 模式变量声明为全局变量,并且在我的代码中使用:

// api
exports.signUp = (req, res) => {
  const user = {
    username: req.body.username,
    firstName: req.body.firstName,
    lastName: req.body.lastName,

  };
  Login.create(user)
    .then(data => res.status(200).send(data))
    .catch(Sequelize.ValidationError, err => res.status(422).send(err.errors[0].message))
    .catch(err => res.status(400).send(err.message));
};

是的,经过大量搜索,我发现有三种数据库方法可以构建 SaaS 产品,

  1. 每个租户的独立数据库
  2. 单独的模式(tables)和所有租户共用一个数据库
  3. 所有租户共享 table 和一个数据库

最后我决定使用选项 2,我转向 Postgresql 而不是 mysql,因为 Postgresql 有基于模式的方法!

现在我的最终代码:

const postgresDB = new Sequelize('postgres://localhost:5432/test_enduser');

postgresDB.authenticate().then((err) => {
  if (err) {
    console.log('There is connection in ERROR.');
  } else {
    console.log('Postgres Connection has been established successfully');
  }
});

postgresDB.define('inventory', {
  name: Sequelize.STRING,
});

const createSchema = () => {
  Business.findAll({
    raw: true,
  }).then((data) => {
    data.forEach((client) => {
      postgresDB.createSchema(client.code).then(() => {
        Object.keys(postgresDB.models).forEach((currentItem) => {
          postgresDB.models[currentItem].schema(client.code).sync();
        });
        // new schema is created
        console.log('Postgres schema created');
      }).catch((err) => {
        console.log(err.message);
      });
    });
  });
};
createSchema();


// apis
exports.getAllBusiness = (req, res) => {
  postgresDB.models.inventory.schema(req.user.code).findAll()
    .then((results) => {
      res.send(results);
    });
};

exports.postBusiness = (req, res) => {
  const user = {
    name: req.body.name,
  };
  postgresDB.models.inventory.schema(req.user.code).create(user)
    .then(data => res.status(200).send(data))
    .catch(Sequelize.ValidationError, err => res.status(422).send(err.errors[0].message))
    .catch(err => res.status(400).send(err.message));
};
  1. 我正在设置我的 postgres 连接
  2. 只是为了测试我正在创建一个名为 "inventory"
  3. 的 table
  4. 在我的应用程序中,一个在线的人来了,他注册了,注册时我将商业代码存储到我的商业 table(商业table 来自单独的数据库,这是一个超级主应用程序数据库),所以我正在查找业务代码并循环并在 postgres

  5. 中制作动态模式
  6. 现在看看我的 api,我正在基于 req.user.code(从登录会话)进行 CRUD,我最终根据特定模式匹配显示数据,

所以最后我为每个客户端都有了干净的独立模式

谢谢!