有一个类似的线程没有具体的解决方案,我认为最好开始一个新的。
我面临的情况是我在RESIN中托管了WebApp(就像Tomcat一样)。到目前为止,我一直在使用db4o开发应用程序,因为我一个人,我需要尽快完成应用程序,我有一个用户数据库和另一个数据库的单个用户(我)的应用程序数据,现在该应用程序几乎完成我即将转向postgresql并且我正在认真考虑每个用户的数据库,即使数据库保存多个应用程序的数据,因为它将处理有点机密数据,我认为拥有单独的数据库将是最好的(安全明智)。已经有一个基本的会话管理,可以在浏览器中存储ID等用户数据。但我想知道如何将其扩展到多个用户/ db。
我正在考虑扩展侦听器类,以保持上下文数据将正确的db对象传递给app实例,或者为此目的设置过滤器。
.UPDATE。
我想更深入地了解我目前的情况。
我有:
包含对某些对象的引用的上下文,其中一个对象连接到数据库并检查用户和密码。
表示servlet(HttpServlet)映射到“/”,其登录表单为POST到/ login。
登录servlet(HttpServlet)映射到“/ login”,它根据上下文中的相应对象检查httpSession用户密码属性,如果匹配则设置包含USERID的httpSession属性并将用户重定向到app本身位于/index-debug.html,如果没有,它会再次创建一个带有登录表单的新html页面。
映射到/index-debug.html的授权和身份验证过滤器,用于验证httpServletRequest的USERID属性,并检查用户是否有权访问该应用。
最后一个DB bean负责读取和写入webApp用户数据DB。当我在webApp中执行某个方法CP2JAVAWS将该方法与bean中的相应方法匹配时,问题是这个bean有一个静态数据库,到目前为止它只允许一个用户。
我想做的是以某种方式允许这个DB bean为每个用户实例化一次,并根据当前登录用户读取和存储相应的数据。
每个用户一个数据库的想法目前被丢弃,但我不知道究竟是怎么回事。
答案 0 :(得分: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框,用数据库分隔用户对你没有帮助。它们可以在数据库之间移动,这可能与在表中的记录之间移动一样容易。最好是真正锁定数据库机器,然后让用户在一个表中共同生活。它更容易扩展,更易于维护,您可以管理波动性。
答案 1 :(得分:2)
您提到Postgres是数据库后端,并且具有名为schemas的功能。这是在数据库中有一个物理数据库和多个模式的地方。我对此的体验来自Rails,但概念是相同的。这种方法可以避免将人们的数据混合在同一组表中,这听起来像是您最关心的问题。我知道你正在使用Java,但watch this talk on Multi-tenant apps in Rails to get a background from Guy Naor关于它如何工作,权衡等等。
以下是一些让您开始使用Postgres模式的具体步骤:
为您将创建的每个架构提出命名约定(例如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);
当您创建数据库bean(使用超类,请参见下文)时,从HttpSession中传递来自User对象的模式名称,然后在每次操作之前执行此SQL以仅将它们隔离到其模式:
myquery2 = "SET search_path TO ?";
myquery2.setString(1,user.search_path);
如果您在公共场所中有一个空的完整架构,那么您希望从搜索路径中省略public,否则您将在搜索路径中拥有2个具有相同名称的表。如果您希望用户搜索路径包含SET search_path TO user_001,public
,那么在创建表格之后,删除除用户以外的所有公共数据表以及您需要的任何元信息。
如果您使用备用路由并将所有用户数据放在一组表中,那么最好的方法是在每个表中使用user_id并编写SQL以使用每个< / em>时间。如果您使用传统规范化并进行连接以获取user_id,那么您最好确保不会意外错过连接,否则用户将开始看到彼此的数据。
Postgres架构功能允许您锁定用户仅访问自己的数据。找出基础知识后,使用Java中的超类编写上面的步骤3,以便每个MyTableDBBean从MasterDBBean扩展,并使用超类构造函数将搜索路径隔离到用户的模式。然后,在代码中只有一个位置可以完成此操作,并且您不必记住每个表或查询除了业务逻辑之外还要执行任何操作。