从连接池获取数据库连接

发布于 2024-10-08 15:47:49 字数 832 浏览 1 评论 0原文

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

样本是这样的。每次调用服务方法时,系统都会在 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() 方法,但我认为这不是最佳选择。

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.

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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

惟欲睡 2024-10-15 15:47:49

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 模式。

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

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:

<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):

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.

灯下孤影 2024-10-15 15:47:49

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

例如

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 查找开销。

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.

夢归不見 2024-10-15 15:47:49

我刚刚对此做了一些测试,发现 jndi 查找时间并不那么繁重。这里大约 1 秒内进行 50.000 次查找。

所以在很多情况下,我根本看不出缓存数据源的原因。

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

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.

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

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.

浅浅 2024-10-15 15:47:49

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

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

希望这有帮助。

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.

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.

Hope this helps.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文