Получить соединение с базой данных из пула соединений
Я реорганизую другие коды. Единственное, что я замечаю, это то, как система получает соединение из пула соединений.
Пример такой. При каждом вызове метода службы система создает контекстный поиск в 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 и регистрируется в реестре. Следующий вызов просто вытащит объект из реестра.
Надеюсь, что это поможет.