servlet 上下文的多个动态数据源

Posted

技术标签:

【中文标题】servlet 上下文的多个动态数据源【英文标题】:Multiple dynamic data sources for a servlet context 【发布时间】:2009-05-31 18:52:51 【问题描述】:

我正在开发一个 java servlet Web 应用程序,该应用程序管理来自多个数据库(结构相同)的信息,每个数据库对应于不同的“业务”。用户选择存储在会话中的“当前业务”,应用程序可以显示或修改该“当前业务”。

我想以动态方式使用 tomcat 资源,以便使用 jndi 访问这些业务。通过这种方式,我可以在 servlet 中使用 jstl sql 标记或上下文查找。我无法在 web.xml 文件中定义每个资源,因为它们存储在 SQL 表中。最终结果是能够编写具有以下行的简单 jsp:

<%@ taglib uri="http://java.sun.com/jstl/sql" prefix="sql" %>

<sql:query var = "users" dataSource="sources/$sessionScope.currentBusiness">
  select id, firstName, lastName FROM user
</sql:query>

或者可以有这样的行的servlet

String request.getSession().getAttribute("currentBusiness");

Context initial = new InitialContext();
Context context = (Context) initial.lookup("java:comp/env");
DataSource source = (DataSource) context.lookup("sources/" + currentBusiness);

我可以在哪里获得“当前业务”的正确数据源。

我尝试编写自己的从 javax.naming.spi.ObjectFactory 派生的 ObjectFactories,但没有成功。关于如何轻松做到这一点的任何指示?

【问题讨论】:

【参考方案1】:

我最终选择了以下由 SessionListener 和 Servlet 组成的解决方案,其工作方式如下。 SessionListener 的形式如下:

public class SessionListener implements HttpSessionListener 

  public void sessionCreated(HttpSessionEvent event) 

    HttpSession session = event.getSession();

    // get list of possible data sources available to this session
    List<DataSource> sources = new ArrayList<DataSource>();
    ... code to get the available sources

    // get the current data source
    DataSource source = null;
    ... code to get the current source                               
    source = sources.get(0); // for example

    // setup the session attributes
    session.setAttribute("availableSources", sources);
    session.setAttribute("currentSource", source); 

  


每当用户登录并创建会话时,可用数据源列表和当前数据源列表都会放入会话中。这是在会话级别完成的,因为数据源依赖于用户登录。现在可以从应用程序内部访问它们。为了更改当前的数据源,我使用这个简化版本创建了一个 Servlet:

public abstract class BoxletServlet extends HttpServlet 

  protected void doGet(HttpServletRequest request, HttpServletResponse response) 
    throws ServletException, IOException 

    HttpSession session = request.getSession(true);
    String s = request.getParameter("source");

    // based on 's' choose from the available DataSource
    List<DataSource> sources = (List<DataSource>) session.getParameter("availableSources");
    Source source = chooseFrom(sources, s);                                                       
    session.setParameter("currentSource", source);          

    // forward to a page saying that the DataSource changed

  

有了这个实现,现在可以创建以下 jsps:

<%@ taglib uri="http://java.sun.com/jstl/sql" prefix="sql" %>

<sql:query var = "users" dataSource="$sessionScope.currentSource">
  select id, firstName, lastName FROM user
</sql:query>

希望对其他人有所帮助。

【讨论】:

【参考方案2】:

在ServletContextListener 中创建数据源并将它们放在ServletContext 中。

【讨论】:

你将如何通过 JNDI 接口访问它? 你不能这样做。也许在同一个监听器中你可以使用 context.bind(name, object) ? 忘记了。你能用成熟的 Tomcat 更改上下文工厂吗?不过不知道是怎么做到的。【参考方案3】:

这种方法肯定会“奏效”,但我认为为每个企业建立一个单独的、相同的数据库的概念似乎是错误的。当然,能够在模式中的某处描绘业务似乎是可能的。以这种方式将它们分开需要每个企业都有一个新的数据库,而架构只需要一个新的企业标识符。

我还认为,跨业务数据挖掘的任何可能性都会丢失,除非您将来自不同数据库的数据 ETL 到一个维度多维数据集中以进行临时报告和查询。

而 JSTL 标签应该只用在最简单的 web 应用程序中。当您放弃中间层的验证时,您就会面临 SQL 注入攻击的可能性。

更新:

你必须在你的 web.xml AFAIK 中声明资源,所以每当你有一个新的数据库时,你必须停止应用程序,配置新的 JNDI 源,然后重新启动 Tomcat。我希望您是集群的,因为每次添加新业务/数据库时,所有以前的客户端都会受到应用程序关闭的影响。

【讨论】:

多个数据库的限制是它们代表多个公司的不同管理系统(不受我控制)。我正在为所有公司(不是很迷人)编写一个应收账款跟踪模块,并且需要分别访问每个公司。至于 jstl sql 标签,我只是用它们来显示每个公司的信息。

以上是关于servlet 上下文的多个动态数据源的主要内容,如果未能解决你的问题,请参考以下文章

具有实体框架的动态多数据库上下文

Servlet验证Mysql数据库,实现JSP页面数据动态显示

Servlet验证Mysql数据库,实现JSP页面数据动态显示

使用动态上下文数据时如何用新的 React 上下文 api 替换旧的 React contextTypes?

Entity Framework 6 的动态 MySQL 数据库连接

servlet中如何发送ajax请求并动态拼接数据到html中