代码之家  ›  专栏  ›  技术社区  ›  Ricardo Marimon

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

  •  0
  • Ricardo Marimon  · 技术社区  · 15 年前

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

    我希望以动态方式使用Tomcat资源,以便使用JNDI访问这些业务。通过这种方式,我可以在servlet中使用JSTLSQL标记或上下文查找。我不能在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派生的objectfactory,但没有成功。关于如何轻松做到这一点有什么建议吗?

    3 回复  |  直到 15 年前
        1
  •  2
  •   Ricardo Marimon    15 年前

    我最终确定了以下解决方案,包括一个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
    
      }
    

    }

    通过这种实现,现在可以创建以下JSP:

    <%@ 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
  •  1
  •   Robert Munteanu    15 年前

    在中创建数据源 ServletContextListener 把它们放在 ServletContext .

        3
  •  0
  •   duffymo    15 年前

    这种方法当然会“起作用”,但是对于每一个业务来说,一个单独的、相同的数据库的概念在我看来是错误的。当然,能够在模式中的某个地方描述业务似乎是可能的。以这种方式分离它们需要为每个业务创建一个新的数据库,其中模式只需要一个新的业务标识符。

    我还认为,跨业务数据挖掘的任何可能性都将丢失,除非您将来自不同数据库的数据ETL到用于特殊报告和查询的维度多维数据集。

    JSTL<SQL>标记只能用于最简单的Web应用程序。当您放弃中间层的验证时,您就有可能受到SQL注入攻击。

    更新:

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