java 从连接池中获取数据库连接

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/4491596/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-30 06:36:43  来源:igfitidea点击:

Get database connection from a connection pool

javajspservlets

提问by Mark Estrada

I am refactoring others code. The one thing I notice is that of the manner on how the system is getting a connection from the connection pool.

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

Sample is like this. On every call of the service method, the system is making a context lookup on the JNDI for the datasource.

样品是这样的。每次调用服务方法时,系统都会在 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();
        }
    }
}

I do think that there is a performance hit on doing this every time. I am thinking of another way around these on how to retrieve a connection from a connection pool.

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

I am thinking about using the servlet's init()method but I think that is not optimal.

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

回答by BalusC

Do it once in a ServletContextListenerinstead of everytime in init()of many servlets. The contextInitialized()method is executed only once during webapp's startup.

ServletContextListenerinit()许多 servlet 中执行一次而不是每次执行。该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);
    }
}

Configure it as follows in web.xml:

配置如下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>

You can obtain it in your servlet as follows (init()or doXXX()method, you choose):

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

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

I'd however refactor it a step further, JDBC code should preferably be placed in its own classes, not in servlets. Lookup the DAO pattern.

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

回答by Codemwnci

The method I have used in the past is to create a singleton class that holds the datasource

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

E.g.

例如

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();
    }
}

This means that you have a shared reference to your datasource, taking away the jndi lookup overhead.

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

回答by Martin Wickman

I just did some testing with this, and found that jndi lookup time is not that heavy. 50.000 lookups in about 1 sec here.

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

So in many cases, I don't see a reason for caching the DataSource at all.

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

Problem with caching is that you might end up with a stale DataSource, forcing you to restart your app if you change anything related to the datasource definition.

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

回答by Buhake Sindi

Adding to what's said, there's a design pattern called Service Locator, which is a basically a singleton containing a registry called "service" that holds your JNDI objects.

除了所说的内容之外,还有一个称为Service Locator的设计模式,它基本上是一个单例,包含一个称为“服务”的注册表,该注册表包含您的 JNDI 对象。

Basically, if the object isn't found in the registry, the service is taken from the JNDI pool and registered in the registry. The next call will simply pull the object from registry.

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

Hope this helps.

希望这可以帮助。