【问题标题】:Get database connection from a connection pool从连接池中获取数据库连接
【发布时间】:2011-05-28 08:32:27
【问题描述】:

我正在重构其他代码。我注意到的一件事是系统如何从连接池获取连接的方式。

样品是这样的。每次调用服务方法时,系统都会在 JNDI 上为数据源进行上下文查找。

public class CheckinServlet extends HttpServlet {

    public void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {

        try {
            //Obtain Connection
            InitialContext initialContext = new InitialContext();
            javax.sql.DataSource ds = (javax.sql.DataSource) initialContext
                    .lookup("jdbc/mysqldb");
            java.sql.Connection conn = ds.getConnection();
            //business logic
            //redirect
        } finally {
            conn.close();
        }
    }
}

我确实认为每次执行此操作都会对性能造成影响。我正在考虑如何从连接池中检索连接的另一种方法。

我正在考虑使用 servlet 的 init() 方法,但我认为这不是最佳选择。

【问题讨论】:

    标签: java jsp servlets


    【解决方案1】:

    我只是对此做了一些测试,发现 jndi 查找时间并没有那么重。在此处大约 1 秒内进行 50.000 次查找。

    所以在很多情况下,我根本看不到缓存 DataSource 的理由。

    缓存的问题是您最终可能会得到一个陈旧的数据源,如果您更改与数据源定义相关的任何内容,就会迫使您重新启动应用程序。

    【讨论】:

      【解决方案2】:

      在 ServletContextListener 中执行一次,而不是在许多 servlet 中的 init() 中执行一次。 contextInitialized()方法只在webapp启动时执行一次。

      public class Config implements ServletContextListener {
          private static final String ATTRIBUTE_NAME = "config";
          private DataSource dataSource;
      
          @Override
          public void contextInitialized(ServletContextEvent event) {
              ServletContext servletContext = event.getServletContext();
              String databaseName = servletContext.getInitParameter("database.name");
              try {
                  dataSource = (DataSource) new InitialContext().lookup(databaseName);
              } catch (NamingException e) {
                  throw new RuntimeException("Config failed: datasource not found", e);
              }
              servletContext.setAttribute(ATTRIBUTE_NAME, this);
          }
      
          @Override
          public void contextDestroyed(ServletContextEvent event) {
              // NOOP.
          }
      
          public DataSource getDataSource() {
              return dataSource;
          }
      
          public static Config getInstance(ServletContext servletContext) {
              return (Config) servletContext.getAttribute(ATTRIBUTE_NAME);
          }
      }
      

      在web.xml中配置如下:

      <context-param>
          <param-name>database.name</param-name>
          <param-value>jdbc/mysqldb</param-value>
      </context-param>
      <listener>
          <listener-class>com.example.Config</listener-class>
      </listener>
      

      您可以通过以下方式在您的 servlet 中获取它(init() 或 doXXX() 方法,您选择):

      DataSource dataSource = Config.getInstance(getServletContext()).getDataSource();
      

      不过,我会进一步重构它,JDBC 代码最好放在它自己的类中,而不是放在 servlet 中。查找 DAO 模式。

      【讨论】:

      • 您好,先生,感谢您一直以来的详细回答。但有一件事让我一直在思考这个问题。为什么将 Datasource 对象作为上下文范围的参数?我们不能让 getDataSource() 方法成为静态方法吗?我真的很喜欢这个答案,但我想进一步了解这样做的原因。谢谢你..
      • 看看它也是好的设计。 DataSource 特定于单个 Config 实例,而不是多个 Config 实例。尽管在这种特殊情况下只有一个。
      • 调用 contextDestroyed(ServletContextEvent) 时数据库连接是否关闭?
      • @robert:您绝对不应该让连接保持打开那么长时间。您需要根据正常的 JDBC 习惯自行关闭它:在打开它的 try 块的 finally 块中。请注意DataSource != Connection。另请参阅此答案:stackoverflow.com/questions/2313197/… 以后有问题请按,我们值得加分:)
      • 我正在考虑按 ,但没有。下次我会的!
      【解决方案3】:

      除此之外,还有一种称为Service Locator 的设计模式,它基本上是一个单例,其中包含一个名为“服务”的注册表,用于保存您的 JNDI 对象。

      基本上,如果在注册表中找不到对象,则从 JNDI 池中获取服务并在注册表中注册。下一次调用将简单地从注册表中提取对象。

      希望这会有所帮助。

      【讨论】:

        【解决方案4】:

        我过去使用的方法是创建一个保存数据源的单例类

        例如

        public class DatabaseConnectionManager {
        
            DataSource ds;
        
            public void init() {
                InitialContext initialContext = new InitialContext();
                ds = (javax.sql.DataSource)initialContext.lookup("jdbc/mysqldb");
            }
        
            public Connection getConnection() {
                if(ds == null) init();
        
                return ds.getConnection();
            }
        }
        

        这意味着您拥有对数据源的共享引用,从而消除了 jndi 查找开销。

        【讨论】:

          猜你喜欢
          • 2013-04-25
          • 2014-04-09
          • 1970-01-01
          • 1970-01-01
          • 2015-06-27
          • 2018-11-25
          • 1970-01-01
          • 2015-08-09
          • 1970-01-01
          相关资源
          最近更新 更多