Закриття підключень JDBC в басейні


109

Наш стандартний розділ коду для використання JDBC - це ...

Connection conn = getConnection(...);
Statement  stmt = conn.conn.createStatement (ResultSet.TYPE_SCROLL_INSENSITIVE,
                                                ResultSet.CONCUR_READ_ONLY);
ResultSet  rset = stmt.executeQuery (sqlQuery);

// do stuff with rset

rset.close(); stmt.close(); conn.close();

Запитання 1: Якщо ви користуєтеся Connection Pool, чи слід закривати з'єднання в кінці? Якщо так, то чи не втрачена мета об’єднання? А якщо ні, то як DataSource знає, коли певний екземпляр Connection звільняється і може бути використаний повторно? Я трохи розгублений у цьому, будь-які вказівки оцінили.

Питання 2: Чи наведений нижче метод чимось близький до стандартного? Схоже, спроба отримати з'єднання з пулу, і якщо DataSource неможливо встановити, використовуйте старомодний DriverManager. Ми навіть не впевнені, яка частина виконується під час виконання. Повторюючи вищезазначене питання, чи слід закривати З'єднання, виходячи з такого методу?

Дякую, - МС.

synchronized public Connection getConnection (boolean pooledConnection)
                                                        throws SQLException {
        if (pooledConnection) {
                if (ds == null) {
                        try {
                                Context envCtx = (Context)
                                        new InitialContext().lookup("java:comp/env");
                                ds = (DataSource) envCtx.lookup("jdbc/NamedInTomcat");
                                return ds.getConnection();
                        } catch (NamingException e) {
                                e.printStackTrace();
                }}
                return (ds == null) ? getConnection (false) : ds.getConnection();
        }
        return DriverManager.getConnection(
                "jdbc:mysql://"+ipaddy+":"+dbPort +"/" + dbName, uName, pWord);
}

Редагувати: Я думаю, що ми отримуємо об'єднане з'єднання, оскільки ми не бачимо сліду стека.

Відповіді:


121

Якщо ви користуєтесь Connection Pool, чи слід закривати з'єднання наприкінці? Якщо так, то чи не втрачена мета об’єднання? А якщо ні, то як DataSource знає, коли певний екземпляр Connection звільняється і може бути використаний повторно? Я трохи розгублений у цьому, будь-які вказівки оцінили.

Так, безумовно, потрібно також закрити об'єднане з'єднання. Це фактично обгортка навколо фактичного з'єднання. Він під кришками відпустить фактичне з'єднання назад до пулу. Далі, до пулу, вирішувати, чи дійсно з'єднання буде фактично закрито або повторно використане для нового getConnection()дзвінка. Отже, незалежно від того, використовуєте ви пул підключень чи ні, завжди слід закривати всі ресурси JDBC у зворотному порядку в finallyблоці tryблоку, де ви їх придбали. У Java 7 це можна додатково спростити за допомогою try-with-resourcesоператора.


Чи є наступний метод чимось близьким до стандартного? Схоже, спроба отримати з'єднання з пулу, і якщо DataSource неможливо встановити, використовуйте старомодний DriverManager. Ми навіть не впевнені, яка частина виконується під час виконання. Повторюючи вищезазначене питання, чи слід закривати З'єднання, виходячи з такого методу?

Приклад досить страшний. Вам потрібно лише знайти / ініціалізувати DataSourceлише один раз під час запуску програми в якомусь конструкторі / ініціалізації загальноприйнятого класу конфігурації БД. Потім просто зателефонуйте getConnection()на один і той же джерело даних протягом усього часу життя програми. Немає потреби в синхронізації і недійсних перевірок.

Дивитися також:


Ось що це робить (ініціалізувати один раз), чи не так? ds - це змінна інстанція, і якщо (ds == null) ... це частина ініціалізації.
Манідіп Сенгупта

Зробити чеки щоразу у методі get, як getConnection()це дивно. Просто зробіть це в блоці c'tor або ініціалізації того самого класу, без синхронізації / nullchecks. Її зателефонують лише один раз. Для отримання додаткових підказок та прикладів, які можна відбити, ця стаття може бути корисною.
BalusC

Відмінна стаття, BalusC. Клас, з яким я маю справу, в значній мірі реалізує Data Data, використовуючи DTO. Я згоден з вами, ініціалізація повинна бути в конструкторі. Тепер цей клас має тону методів, кожен з conn, stmt та rset як локальні змінні, з'єднання є в пробному блоці, і, нарешті, є однорядковий виклик csrClose (conn, stmt, rset), де всі 3 закриті (у зворотному порядку). Тепер, DTO, який ви розробляєте у прикладі, є дзеркальним зображенням рядка таблиці БД. У нас є складні запити SQL з приєднаннями (та іншими пунктами), чи є у вас стаття про те, як розробити DAO для таких результатів?
Манідіп Сенгупта

2
@yat: ОБОВ'ЯЗКОВО зателефонувати close()на них у finallyблок того самого tryблоку, що і там, де ви їх придбали / створили. Це абсолютно незалежно від того, є це об'єднання чи ні.
BalusC

1
@iJava: цей басейн написаний любителем, який абсолютно не має уявлення, що він робить. Ігноруйте це і вирушайте до справжньої бібліотеки. Наприклад HikariCP.
BalusC

22

Пули зазвичай повертають вам обернутий об'єкт Connection, де метод закриття () перекрито, як правило, повернення З'єднання в пул. Дзвінок закрити () добре, ймовірно, все ще потрібен.

Метод close (), ймовірно, виглядатиме так:

public void close() throws SQLException {
  pool.returnConnection(this);
}

Для вашого другого питання ви можете додати реєстратор, щоб показати, чи працює нижній блок. Я б міг уявити, хоча ви хочете лише так чи інакше налаштувати підключення до вашої бази даних. Ми використовуємо виключно пул для доступу до бази даних. У будь-якому випадку закриття з'єднання буде досить важливим для запобігання протікань.


Я погоджуюсь, у нас є лісоруб, і це теж можна використати. Мені потрібно трохи вивчити, як можна обернути Об'єкт, переосмислити його метод close (), але все одно підтримувати те саме ім’я класу (Connection)
Манідіп Сенгупта,

1
Calling close() is OK and probably still required., якщо не зателефонувати близько, витік з'єднання, якщо тільки пул не реалізує якусь стратегію відновлення
svarog

0

Насправді, найкращий підхід до управління з’єднаннями - це не розміщувати їх у будь-якому коді.

Створіть клас SQLExecutor, який є єдиним місцем, яке відкриває та закриває з'єднання.

Потім весь інший додаток завантажує заяви у виконавця, а не отримує з'єднання з пулу та керує ними (або керує ними неправильно) всюди.

Ви можете мати стільки примірників виконавця, скільки хочете, але ніхто не повинен писати код, який відкриває і закриває зв’язки від свого імені.

Зручно, це також дозволяє реєструвати весь свій SQL з одного набору коду.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.