Получить соединение с базой данных из пула соединений

Я реорганизую другие коды. Единственное, что я замечаю, это то, как система получает соединение из пула соединений.

Пример такой. При каждом вызове метода службы система создает контекстный поиск в 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();
        }
    }
}

Я действительно думаю, что каждый раз ударяем производительность. Я думаю о другом способе их подключения к пулу соединений.

Я думаю об использовании метода сервлета init(), но я думаю, что это не оптимально.

Ответы

Ответ 1

Сделайте это один раз в ServletContextListener вместо каждого раза в 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>

Вы можете получить его в своем сервлете следующим образом (init() или doXXX() метод, который вы выбираете):

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

Я бы реорганизовал его еще дальше, JDBC-код желательно размещать в своих классах, а не в сервлетах. Найдите шаблон DAO.

Ответ 2

Метод, который я использовал в прошлом, - создать одноэлементный класс, который содержит источник данных

например.

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.

Ответ 3

Я просто проверил с этим тестирование и обнаружил, что время поиска jndi не так уж тяжело. 50 000 поисковых запросов за 1 секунду здесь.

Поэтому во многих случаях я не вижу причин для кэширования DataSource вообще.

Проблема с кэшированием заключается в том, что вы можете получить устаревший DataSource, заставив вас перезапустить приложение, если вы измените что-либо, связанное с определением источника данных.

Ответ 4

Добавляя к сказанному, есть шаблон проектирования Service Locator, который является в основном одноэлементным, содержащим реестр, называемый "служба", который содержит ваши объекты JNDI.

В принципе, если объект не найден в реестре, служба берется из пула JNDI и регистрируется в реестре. Следующий вызов просто вытащит объект из реестра.

Надеюсь, что это поможет.