Подготовленные операторы вместе с пулами подключений - PullRequest
8 голосов
/ 23 мая 2011

У меня есть вопрос, касающийся общего использования подготовленного оператора вместе с пулами соединений.

Подготовленные операторы обычно привязаны только к одному соединению. В нашем приложении PreparedStatement создается при запуске и выполняется позже.

Если во время выполнения какого-либо конкретного подготовленного оператора соединение, связанное с подготовленным оператором, занято выполнением других операторов, кроме того, как будет выполняться этот требуемый оператор. Этот оператор будет ожидать освобождения соединения или этот оператор будет данное предпочтение в исполнении?

Обновление

Я проверил это, выполнив функцию SLEEP () с базой данных Apache derby, которая вызывает функцию сна java в классе TimeHandlingTest.

CREATE FUNCTION SLEEP () ВОЗВРАЩАЕТ INTEGER ЯЗЫК СТИЛЬ ПАРАМЕТРА JAVA JAVA NO SQL EXTERNAL NAME 'com.derby.test.TimeHandlingTest.sleep';

И сделал два подготовленных оператора из одного соединения и вызвал функцию Sleep () из одного подготовленного оператора и простой выбор SQL с другим. Простой выбор SQL занял почти то же самое время (10 с), для которого спал первый подготовленный оператор. Это означает, что один объект соединения не может быть использован для выполнения более чем одним подготовленным оператором одновременно. Пожалуйста, исправьте меня, если я ошибаюсь.

Ответы [ 5 ]

8 голосов
/ 23 мая 2011

Вы не можете вернуть Connection в пул, если планируете использовать PreparedStatement.

Другими словами: вы можете использовать только PreparedStatement, построенный из Connection, который у вас есть на данный момент.

4 голосов
/ 23 мая 2011

Значение PreparedStatement заключается в способности самой базы данных создавать план выполнения для оператора, который можно повторно использовать для произвольных параметров и, таким образом, является общим по своей природе (конечно, для этого необходимо использовать параметры в своем утверждении, например,

PreparedStatement pstmt = con.prepareStatement("UPDATE EMPLOYEES
                               SET SALARY = ? WHERE ID = ?");
pstmt.setBigDecimal(1, 153833.00);
pstmt.setInt(2, 110592);

Если, с другой стороны, вы будете использовать конкатенацию строк для вставки значений параметров в код SQL, база данных не сможет построить общий план выполнения, поэтому не будет никакой разницы, если выиспользуйте PreparedStatement или Statement, например,

PreparedStatement pstmt = con.prepareStatement("UPDATE EMPLOYEES
                               SET SALARY = 1200 WHERE ID = 3");

не сможет использовать преимущество PreparedStatements.

Ваш вопрос подразумевает, что вы хотите повторно использовать объект PreparedStatement, который не является необходимымКонечно, если вы можете использовать объект PreparedStatement для обновления нескольких значений и т. Д., Это более эффективное использование ресурсов. Тем не менее, продолжительность жизни (или, по крайней мере, полезная продолжительность жизни) PreparedStatement связана с подключением, например, если вы вызываете conn.близко() PreparedStatement становится бесполезным.Тем не менее большинство хороших драйверов в ситуации пула снова используют одни и те же объекты PreparedStatement.Короче говоря, не кэшируйте PreparedStatement независимо от соединения.

2 голосов
/ 23 мая 2011

Предполагая, что это многопоточное приложение, объекты Connection обычно связаны с одним потоком в любой момент времени.Connection объекты, полученные потоком, не возвращаются в пул, пока они не будут закрыты.Это относится как к оболочке логического соединения (которая обычно возвращается источником данных, управляемым сервером приложений) к приложению, так и к физическому соединению.Кроме того, физические соединения могут совместно использоваться несколькими логическими соединениями, если они являются частью одной и той же транзакции.

Это означает, что если дескриптор логического соединения возвращается в ваше приложение, необязательно, чтобы базовый физическийсоединение такое же и оспаривается (если только оно не является частью одной и той же транзакции).Если ожидается, что ваше приложение будет обрабатывать одновременных пользователей без каких-либо хлопот, объект Connection будет создан в каждом потоке, начинающем транзакцию, и этот объект не будет использоваться для всех потоков.В рамках этого процесса различные физические соединения в пуле будут выполнять запросы SQL, связанные с подготовленными операторами, в нескольких потоках, опять же, без каких-либо конфликтов.

1 голос
/ 23 мая 2011

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

0 голосов
/ 23 мая 2011

Одним из способов решения этой проблемы является поддержание кэша, в котором соединения отображаются в подготовленные операторы. Когда вы получаете соединение из пула, проверьте, сопоставлено ли оно с подготовленным оператором, который должен быть выполнен. Если нет, передайте подготовленный оператор в драйвер JDBC, чтобы он был скомпилирован. Затем сопоставьте его с подключением. Недостатком этого подхода является то, что несколько соединений могут получить копии одного и того же подготовленного оператора. Но, похоже, это то, что делают некоторые J2EE-серверы .

...