0

有一个类似的线程没有具体的解决方案,我认为最好开始一个新的。

我面临的情况是,我在 RESIN 中托管了一个 WebApp(就像我猜的 Tomcat)。到目前为止,我一直在使用 db4o 开发应用程序,因为我一个人,我需要尽快完成应用程序,我有一个用于用户的数据库和另一个用于单个用户(我)的应用程序数据的数据库,现在应用程序几乎完成我将要迁移到 postgresql 并且我正在认真考虑每个用户的数据库,即使数据库保存多个应用程序的数据,因为它将处理有点机密的数据,我认为拥有单独的数据库将是最好的(安全方面)。已经有一个基本的会话管理,可以在浏览器中存储用户数据,如 ID。但我想知道如何将它扩展到多个用户/数据库。

我正在考虑扩展保存上下文数据的侦听器类,以将正确的 db 对象传递给应用程序实例,或者为此目的设置一个过滤器。

。更新。

我想更深入地了解我目前拥有的东西。

我有:

包含对某些对象的引用的上下文,其中一个对象连接到数据库并检查用户和密码。

Presentation servlet (HttpServlet) 映射到具有 POST 到 /login 的登录表单的“/”。

登录 servlet (HttpServlet) 映射到“/login”,它检查 httpSession 用户密码属性与位于上下文中的相应对象是否匹配,如果匹配,则设置一个包含 USERID 的 httpSession 属性并将用户重定向到应用程序本身所在的位置在 /index-debug.html 如果没有,它会再次创建一个带有登录表单的新 html 页面。

映射到 /index-debug.html 的授权和身份验证过滤器验证 USERID 属性的 httpServletRequest 并检查用户是否有权访问应用程序。

最后是一个负责读取和写入 webApp 用户数据 DB 的 DB bean。当我在 webApp CP2JAVAWS 中执行某个方法时,将该方法与 bean 中的相应方法相匹配,问题是这个 bean 有一个静态数据库,到目前为止它只允许一个用户。

我想做的是以某种方式允许这个 DB bean 为每个用户实例化一次,并根据当前登录的用户读取和存储相应的数据。

每个用户一个数据库的想法目前已被放弃,但我不知道如何实现这一点。

4

2 回答 2

2

树脂!我已经有一段时间没有听说过 Resin 了,也没有使用过 Resin。=)

我已经看到 Stack Overflow 上经常出现每个系统用户拥有一个数据库的想法。反应通常是相同的——这不是一个好主意。

原因有很多,但我会坚持规模、可维护性和易变性。

规模

一些数据库对它们可以拥有的数据库数量有限制。我不知道单个 Postgres 实例可以拥有多少个数据库。

此链接(https://dba.stackexchange.com/questions/23971/maximum-number-of-databases-for-single-instance-of-postgresql-9)表示有人在一个实例上获得了 10,000 个数据库。

我想说随着时间的推移,一个网站获得一百万用户(当然不是全部活跃)并不少见。换句话说,我敢打赌你的用户数量会在某个时候打破 Postgres,每个用户只有一个数据库。

可维护性

假设您只需要 10,000 个用户,因此您可以创建 10,000 个数据库。当您想更新每个数据库中的表时会发生什么?推出这些更改很痛苦。

通常发生的情况是您将编写一个脚本来接触每个数据库,即使您对其进行了测试,脚本在中途死掉了,现在您被困在绝望的几分钟里,一半的表处于一种状态,另一半处于另一种状态状态。

或者更糟糕的是,数据库不同步并且具有与其他数据库不同的架构。现在,您可能拥有多个实时版本的“用户”数据库。

挥发性

用户是善变的。他们今天会注册,然后就再也不会回来了。他们将注册并在两年后再次登录。他们会因为忘记密码而创建多个帐户。

这将很快导致孤立的数据库。您需要(或想要)编写一个脚本来定期清理它们。

此外,一些更现代的数据库(如 MongoDB 和 Couchbase)实际上在创建数据库时会预先分配大部分磁盘/内存。我不相信 Postgres 会这样做,但这是需要考虑的事情。

安全

如果有人入侵了您的 Postgres 框,那么按数据库分隔用户对您没有帮助。它们可以在数据库之间移动,就像在表中的记录之间移动一样容易。最好只是很好地锁定数据库机器,然后让用户一起生活在一个表中。它更容易扩展,更容易维护,并且您可以管理波动性。

于 2013-04-23T23:23:11.193 回答
2

您提到 Postgres 作为数据库后端,并且具有称为模式的功能。这是您在数据库中拥有一个物理数据库和多个模式的情况。我的经验来自 Rails,但概念是相同的。这种方法避免了将人们的数据混合在同一组表中,这听起来像是您最关心的问题。我知道您使用的是 Java,但请观看有关 Rails 中的多租户应用程序的演讲,以从 Guy Naor 那里了解其工作原理、权衡等方面的背景知识。

以下是一些具体步骤,可帮助您开始使用 Postgres 模式:

  1. Postgres 中有一个默认的公共模式。这将是您放置用户身份验证表和任何其他关于用户登录等的通用元数据表的地方。 有关模式如何工作的更多信息,请参阅 Postgres 文档
  2. 为您将创建的每个模式(例如 user_001、user_002 等)提出一个命名约定。预先分配一堆空模式并设置所有表,当用户第一次注册或登录时,您为他们分配一个模式并将模式名称存储在公共模式和用户对象中的用户记录中你在 HttpSession 中。无需为第一次使用的用户运行表创建脚本——这会拖累 Web 应用程序的性能。您只需要保持领先于新用户的速度。例如,您可能有一堆空的 user_standby_1 ... user_standby_100 模式,然后当有人登录或注册时,您将运行以下 sql:

    myquery = "ALTER SCHEMA user_standby_? RENAME TO user_?"; myquery.setString(1,standby_id); myquery.setString(2,user_id);

  3. 当您创建 DB bean 时(为此使用超类,见下文),从 HttpSession 的 User 对象中传递模式名称,然后在每个操作之前执行此 SQL 以仅将它们隔离到它们的模式:

    myquery2 = "SET search_path TO ?";
    myquery2.setString(1,user.search_path);

  4. 如果您在公共中有一个空的完整架构,那么您希望从搜索路径中省略公共,否则您将在搜索路径中有 2 个同名的表。如果您希望SET search_path TO user_001,public在创建表后包含用户搜索路径,请从公共中删除所有数据表,而不是用户和您需要的任何元信息。

  5. 为了维护,编写一个脚本,您可以通过命令行运行以删除空的 user_standby 模式,创建新的 user_standby 模式,并执行与 Rails Migrations for Java相同的操作,以进行较小的表更改。
  6. 对于大型维护活动,最好为每个用户创建新模式,例如 user_v2_001,然后编写脚本来迁移他们的数据。这取决于对表的更改有多复杂。

如果您采用替代路线并将所有用户数据放在一组表中,那么最好的方法是在每个表中都有 user_id 并编写您的 SQL 以每次都使用它。如果您使用传统的规范化并执行连接来获取您的 user_id,那么您最好确保您不会意外错过连接,否则用户将开始看到彼此的数据。

Postgres 模式功能允许您锁定用户仅访问他们自己的数据。搞清楚基础知识后,使用 Java 中的超类编写上面的步骤 3,这样每个 MyTableDBBean 都从 MasterDBBean 扩展,并使用超类构造函数将搜索路径隔离到用户的模式。然后,您的代码中只有 1 个地方可以完成此操作,并且您不必记住每个表或查询来执行业务逻辑以外的任何操作。

于 2013-04-30T14:14:08.183 回答