来自Web应用程序的数据库连接没有连接池

问题描述:

我试图围绕从JSF Web应用程序建立到数据库的JDBC连接的正确方法。我通常的方法是在应用程序服务器中创建一个数据源,并通过我的代码中的JNDI名称连接到它。实质上,所有用户都将在整个会话期间通过池共享相同的数据库用户帐户。来自Web应用程序的数据库连接没有连接池

不幸的是,我正在处理的一个新项目的要求阻止了我这样做。连接到应用程序的每个用户都必须使用唯一凭证登录到RDBMS。我有一个如何实现与此相关的代码的草图,但我并未完全清楚整体架构。 应用程序服务器(Tomcat,Glassfish,WebLogic)是否具有支持此功能的功能?

现在,我似乎可以完成这一任务的唯一方法是让每个用户会话直接创建一个JDBC连接回数据库。虽然我相信这会起作用,但它感觉不对。

我错过了什么吗?

+0

您可能想要检查从['DataSource.getConnection(username,password)'](http://docs.oracle.com/javase/8/docs/api/javax/sql/DataSource.html #getConnection-java.lang.String-java.lang.String-)根本就是共享的(我见过的池和没有的池)。 – 2014-11-02 08:06:01

你错过了什么 - 我非常想:合理的系统设计。 ;)使用数据库凭证管理用户的整个想法恰好适用于管理数据库的一个用例。对于其他所有问题,它会带来更多的问题,因为它会带来更多的问题......所以让我们开始吧......)

BOT:有一个两难的问题。您基本上必须为每个用户创建一个连接池,因为否则每次数据源在连接超时运行时都必须创建与数据库的连接。三次握手加认证不是一件便宜的事情 - 延迟会导致你的表现。虽然有些驱动程序可以进行相应的配置,但总的来说这是一个糟糕的主意,而且大多数驱动程序由于所谓的“关注点分离”而不善于自己管理连接。另一方面,每个连接“池”只需要大约5个连接,因为同一用户不太可能并行执行多个操作。

注意:我知道的唯一一个驱动程序管理连接和池的驱动程序是体面的。

现在问题在于:您无法将连接池附加到会话。不是没有走几英里,我怀疑这是完全可能的。

解决此问题的一个想法是,当用户登录并使用JNDI动态注册时,为用户创建连接池。问题是这不是很有伸缩性(假设你有几百个用户)。因此,当会话终止时(无论是通过注销还是超时),您都必须确保删除该池。另外,代码必须保留。

另一个想法是使用Apache Shiro并编写一个自定义Realm,它只是试图登录数据库来检查凭据,如果失败则抛出AuthenticationExcepion。这里的折衷是你每次都必须初始化连接,这有一些延迟。您的领域甚至可能使用应用程序范围的连接池,并检查数据库元数据以获取身份验证和授权数据。当然,这将使得有必要以特权用户的身份访问数据库 - 这是一个可怕的想法。底线:不管你用哪种方式来看待它,通过数据库管理应用程序认证和授权需求可能会消除应用程序中的认证和授权层,但是反过来需要一个额外的抽象层(你不需要'如果某些数据库机制发生了变化,是否需要更改服务的代码?),当我们看到并将代码绑定到一个数据库时,会产生可伸缩性问题(当然,除非您需要细粒度的权限并且可以与“工作,没有工作”的结果)。

+0

非常感谢您的回复!这些与我在提出要求时所担心的完全一样。我目前的想法(再一次,我意识到这不是理想..)将配置一个非常小的池,在RDBMS中读取用户创建的一组表来检查凭据(不是例如Oracle中的dba_users视图) 。一旦选中了信用卡,应用程序就会创建一个会话。从那里,将为他/她自己的RDBMS凭证创建另一个连接。 – Naitouk 2014-11-02 15:21:17

+0

我认为这是太多的代码来维护。我宁愿去与Shiro和一个自定义领域,这是很容易实现。 – 2014-11-02 18:48:26

我不确定空连接池的开销是多少,也不知道有多少用户参与,但我建议保留连接池的全局列表,配置为低最大连接数(2?)和侵略性空闲超时一直返回到零池连接。然后,当用户登录时,检查他们是否已经有一个由他们的用户名引用的池,如果没有,则创建一个新池并将其保存在池中,然后为该用户的连接使用该池。

这样你就可以以最小的开销获得池的好处。这是否可行取决于您的用户数量。

我当然希望找到最适合您的最低开销池实现 - 有几种可供选择。 c3p0对我自己来说非常棒。

+0

有趣的做法。由于每个用户都将保证拥有100%的唯一用户名,因此我可能需要在注销时销毁池。谢谢你的建议! – Naitouk 2014-11-02 06:16:20