![]() |
| На главную страницу | |
| Форум | |
Пулы Соединений с БД
Если Вы хотите использовать объект
Вы можете создать общий connect (dbtype, serverName, userName, password,
При создании соединения Вы можете специфицировать следующую информацию, либо при
создании
Например, следующий оператор создаёт новый пул БД из 5 соединений с БД Oracle. В этом пуле неподтверждённые транзакции откатываются: pool = new DbPool ("ORACLE", "myserver1", "ENG", "pwd1", "", 5);
Приложение-образец Для многих приложений Вы, возможно, захотите выполнять совместное использование набора соединений несколькими клиентами, или чтобы соединение захватывало несколько клиентских запросов. В этих случаях Вы должны устанавливать соединение на начальной странице Вашего приложения. Это позволит исключить возможные проблемы в тех случаях, когда отдельные клиенты выполняют совместные соединения с БД. Однако для некоторых приложений каждый клиент должен выполнять своё собственное соединение. Как сказано в разделе "Совместное Использование Массива Пулов Соединений," клиенты могут совместно использовать объекты. Если это так, убедитесь, что блокировки используются для управления совместным использованием данных, как указано в разделе "Безопасное Использование Объектов с Помощью Блокировки". В следующей таблице показаны методы объектов
Таблица 8.2 Методы объектов
|
| Sybase | Informix | Oracle | DB2 | ODBC1 | |
|---|---|---|---|---|---|
| 1 Все многопоточные тесты для ODBC были сделаны на MS SQL Server. Если Вы используете другой драйвер ODBC, узнайте у производителя, является ли драйвер многопоточным. |
Эти указания являются критичными для однопоточного доступа. Однако Вы должны
думать об этом даже тогда, когда используете БД с многопоточным доступом.
Однопоточная библиотека БД может иметь существенные
ограничения производительности. Поскольку только один поток имеет доступ к БД в
единицу времени, все прочие потоки обязаны ждать, когда первый поток освободит
соединение с БД, прежде чем один из них сможет получить доступ к БД. Если
доступа ожидают одновременно несколько потоков, каждому придётся ожидать довольно долго.
При разработке доступа к БД Вы должны предусмотреть следующее:
Каждый поток обязан ждать окончания работы другого потока. Чем короче время взаимодействия с БД, тем меньше ожидание.
Ограничения на использование транзакций для клиентских библиотек БД, которые не являются многопоточными:
database() или DbPool(), Вы обязаны
установить максимальное допустимое количество соединений с БД в Вашем
приложении большим, чем количество клиентов, которые, как Вы предполагаете,
будут использовать Ваше приложение. Иначе некоторые клиенты не смогут
установить соединение с БД, и их приложения зависнут.
В любой данный момент времени соединённый объект DbPool или database
и все соединения пула ассоциированы с определённой конфигурацией базы данных. То
есть всё, что находится в пуле, соединено с определённым сервером БД как
отдельный пользователь с отдельным паролем и с определённой БД.
Если Ваше приложение всегда использует одну конфигурацию, то можно использовать
единственный объект DbPool или использовать объект database
и соединяться однократно. В этом случае Вы должны выполнить соединение на
начальной странице Вашего приложения.
Если Вашему приложению требуется несколько конфигураций, или потому что оно обязано соединяться с несколькими БД, или с одной БД, но с разными пользователями, или и то, и другое, Вам необходимо определить, как обслуживать эти конфигурации.
Если Вы используете объект database и несколько соединений, то
выбора у Вас нет. Вы обязаны соединяться, отсоединяться и повторно соединяться с
объектом database каждый раз, когда Вам нужно изменить что-либо в
конфигурации. Вы делаете это под управлением клиентских запросов. В этой
ситуации убедитесь, что используются блокировки, как указано в разделе "Совместное
Использование Объектов с Блокировкой," чтобы получать исключительный доступ
к объекту database. Иначе другой клиентский запрос может отключить
объект до того, как текущий клиентский запрос закончит с ним работу. Хотя Вы и
можете использовать объект database таким образом, лучше будет
всё-таки использовать объекты DbPool.
Если Вы используете объекты DbPool и несколько конфигураций, Вы
также должны соединяться, отсоединяться и повторно соединяться с объектом DbPool.
Однако с объектами DbPool у Вас появится больше возможностей. Вы
можете создавать столько пулов, сколько нужно, и ставить их под контроль объекта project. (См.
в Главе 6, "Обслуживание Сессий" информацию
об объекте project.) Использование нескольких пулов более
эффективно и обычно надёжнее, чем многократное использование единственного пула (как
с объектом database , так и с единственным объектом DbPool).
При определении того, как обслуживать пулы, Вы обязаны учитывать два фактора: ко скольки конфигурациям будут иметь доступ пулы и нужно ли будет одному соединению захватывать несколько клиентских запросов. Если у Вас небольшое количество возможных конфигураций, Вы можете создать отдельные пулы для каждой. В разделе "Совместное Использование Фиксированного Набора Пулов Соединений" обсуждается этот подход.
Если у Вас имеется очень большое или заранее не известное количество конфигураций (например, если все пользователи БД получают свои индивидуальные ID), нужно предусмотреть два варианта. Если одного соединения достаточно для выполнения одного клиентского запроса, Вы можете создавать отдельные пулы на клиентской странице.
Однако иногда соединение должно захватывать несколько клиентских запросов (например, если одна транзакция в БД захватывает несколько клиентских запросов). Возможно также, что Вы просто не хотите повторно соединяться с БД на каждой странице приложения. Если это так, Вы можете создать массив пулов, который используется совместно. В разделе "Совместное Использование Массива Пулов Соединений" обсуждается этот подход.
Независимо от используемого подхода, если Вам больше не нужно отдельное
соединение в пуле, зачистите ресурсы, используемые этим соединением, чтобы оно
стало доступным для других пользователей. Чтобы выполнить это, закройте все
открытые курсоры, хранимые процедуры и результирующие наборы. Верните соединение
обратно в пул. (Вы не должны освобождать соединение, если используете объект database.)
Если Вы не освободили соединение, то при попытке отсоединить пул система будет ожидать, перед тем как реально отсоединиться, возникновения одного из двух условий:
Если Вы создаёте отдельные пулы БД для каждого пользователя, убедитесь, что пул отсоединён, до того как закончить с ним работу. О курсорах см "Манипуляции с Результатами Выполнения Запросов с Помощью Курсоров". О хранимых процедурах и результирующих наборах см. "Вызов Хранимых Процедур".
Часто в приложении небольшой набор пулов соединений используется всеми
пользователями данного приложения. Например, Вашему приложению нужно соединяться
с тремя различными БД или с одной БД, которая использует 4 пользовательских ID,
соответствующих 4 разным департаментам. Если у вас имеется небольшой набор
возможных конфигураций соединения, Вы можете создать отдельный пул для каждой
конфигурации. Для этого используйте объекты DbPool.
Тогда необходимо, чтобы пул работал в течение всего периода существования
приложения, а не просто в течение периода существования клиента или отдельного
клиентского запроса. Вы можете реализовать это, создав каждый пул БД как
свойство объекта project. Например, начальная страница приложения
может содержать эти операторы:
project.engpool = new DbPool ("ORACLE", "myserver1", "ENG",
"pwd1", "", 5, true);
project.salespool = new DbPool ("INFORMIX", "myserver2", "SALES",
"pwd2", "salsmktg", 2);
project.supppool = new DbPool ("SYBASE","myserver3","SUPPORT",
"pwd3", "suppdb", 3, false);
Эти операторы создают три пула для различных групп пользователей приложения.
Пул project.eng содержит 5 соединений Oracle и подтверждает любую
неподтверждённую транзакцию при высвобождении соединения обратно в пул.
Пул project.sales имеет два соединения Informix и откатывает любую
неподтверждённую транзакцию при окончании соединения.
Пул project.supp имеет три соединения Sybase и откатывает любую
неподтверждённую транзакцию при окончании соединения.
Вы должны создавать такой пул как часть начальной страницы приложения. Эта
страница выполняется только при старте приложения. На страницах, доступных
пользователям, Вы не создаёте пул и не изменяете соединение. Вместо этого эти
страницы определяют, к какой группе принадлежит текущий пользователь, и
используют уже установленное соединение из соответствующего пула. Например, в
следующем коде определяется, какую БД использовать (на основе значения свойства userGroup
объекта request), в БД ищется некоторая информация, которая
выводится пользователю, а затем соединение освобождается:
if (request.userGroup == "SALES") {
salesconn = project.salespool.connection("A sales connection");
salesconn.SQLTable ("select * from dept");
salesconn.release();
}
Вы можете также создать пул и изменить соединение на странице, доступной пользователю. В этом случае Вы должны быть осторожны, так как несколько пользователей, осуществляющих одновременный доступ к этой странице, не должны мешать друг другу. Например, только один пользователь должен иметь возможность создавать пул, используемый всеми остальными пользователями. О надёжности совместного использования информации см. раздел "Надёжное Совместное Использование Объектов с Помощью Блокировки".
В разделе
"Совместное Использование Фиксированного Набора Пулов
Соединений" описано, как Вы можете применить свойства объекта project
для совместного использования фиксированного набора пулов соединений. Этот
подход используется, если Вам в процессе разработки уже известно количество
необходимых пулов соединений и Вам нужно только небольшое количество соединений.
Часто нельзя предугадать заранее количество необходимых пулов соединений. В других случаях это возможно, но это количество недопустимо велико. Например, предположим, что для каждого потребителя, имеющего доступ к Вашему приложению, приложение проверяет пользовательский профиль на предмет определения того, какую информацию из БД вывести. Вы можете дать каждому потребителю уникальный пользовательский идентификатор ID для БД. Такое приложение требует, чтобы каждый пользователь имел свой набор параметров соединений (соответствующий различным пользовательским ID в БД) и, соответственно, разные пулы соединений.
Вы можете создать объект DbPool и соединять и отсоединять его на
каждой странице приложения. Это будет работать, только если одно соединение не
должно захватывать несколько клиентских запросов. Иначе эта ситуация должна
обрабатываться по-разному.
Для данного приложения, вместо создания фиксированного набора пулов соединений
на начальной странице приложения или пула на каждой клиентской странице, Вы
создаёте одно свойство объекта project, которое будет содержать
массив пулов соединений. Доступ к элементам этого массива осуществляется по
ключу на базе определённого пользователя.
Во время инициализации Вы создаёте массив, но не помещаете в него элементы (поскольку
никто ещё не пытался использовать приложение), как показано здесь:
project.sharedPools = new Object();
Когда пользователь впервые стартует приложение, оно получает идентифицирующий
пользователя ключ. На основе этого ключа приложение создаёт объект пула DbPool
и сохраняет его в массиве пулов. Имея данный пул соединений, оно может либо
соединяться на каждой странице, либо устанавливать соединение так, как описано в
разделе "Обслуживание Соединения по Запросам." Следующий
код создаёт пул либо получает уже созданный, проверяет его соединение и работает
затем с БД:
// Генерируется уникальный индекс для обращения к данному клиенту, если это
// ещё не было сделано на другой странице. О функции ssjs_generateClientID см.
// "Уникальное Обращение к Объекту client". if client.id == null {
client.id = ssjs_generateClientID();
}
// Если пула для данного клиента ещё нет, он создаётся
// и производится его соединение с БД. project.lock();
if (project.sharedPools[client.id] == null) {
project.sharedPools[client.id] = new DbPool ("ORACLE",
"myserver", user, password, "", 5, false);
}
project.unlock();
// Для удобства устанавливается переменная для этого пула.
var clientPool = project.sharedPools[client.id];
// Теперь у Вас есть пул: посмотрим, соединён ли он. Если нет, попытаемся соединить его.
// Если это не удаётся, перенаправляем на специальную страницу,
// чтобы проинформировать пользователя.
project.lock();
if (!clientPool.connected()) {
clientPool.connect("ORACLE", "myserver", user, password,
"", 5, false);
if (!clientPool.connected()) {
delete project.sharedPools[client.id];
project.unlock();
redirect("noconnection.htm");
}
}
project.unlock();
// Если Вы дошли до этого места, Вы успешно соединились и
// можете работать с БД.
clientConn = clientPool.connection();
clientConn.SQLTable("select * from customers");
// ... другие операции с БД ...
// Всегда освобождайте соединение, если оно Вам больше не нужно.
clientConn.release();
}
Когда пользователь в следующий раз войдёт в приложение (например, с другой
страницы приложения), он использует тот же самый код и получит сохранённый пул
соединений и (возможно, сохранённый,) объект Connection из объекта project.
Если Вы используете ssjs_generateClientID и сохраняете ID в объекте client,
Вам может понадобиться защита от вторжения через доступ к этому ID и,
следовательно, к закрытой информации.
Объект sharedConns, использованный в этом примере кода, не является
предопределённым объектом
JavaScript. Он просто создан в этом примере и может иметь другое имя по Вашему
выбору.
Как только Вы создали пул соединений, клиентская страница может получить доступ
к индивидуальному соединению из пула. Если Вы используете объект database,
соединение в данном объекте является неявным; то есть Вы используете методы
объекта database для доступа к соединению. Если, однако, Вы
используете объекты DbPool, соединение инкапсулируется в объекте Connection,
который Вы получаете через вызов метода объекта DbPool. Например, в
следующем пуле:
project.eng = new DbPool ("ORACLE", "myserver", "ENG", "pwd1", "", 5);
Вы можете получить соединение из пула с помощью такого вызова метода:
myconn = project.eng.connection ("My Connection", 60);
Оба параметра метода являются необязательными. Первый это имя соединения (используется
при отладке); второй это целое число, обозначающее таймаут в секундах. В этом
примере, если пул имеет доступное соединение или если оно становится доступным в
течение 60 секунд, это соединение присваивается переменной myconn.
Если соединение не становится доступным в течение указанного периода, этот метод
возвращается без соединения. Дополнительно об ожидании получения соединения из
пула см. раздел "Ожидание Соединения". О том, что делать,
если соединение не получено, см. "Запрашивание Незанятого
Соединения".
Если Вы закончили использование соединения, возвратите его в пул путём вызова
метода release объекта Connection. (Если Вы
используете объект database, Вам не нужно самостоятельно
освобождать соединение). Прежде чем вызвать метод release, закройте
все открытые курсоры, хранимые процедуры и результирующие наборы. Если Вы
вызываете метод release, система ожидает, когда всё закроется, и
возвращает затем соединение в пул базы данных. После этого соединение доступно
следующему пользователю. Об использовании курсоров см. "Манипуляции
с Результатами Запросов с Помощью Курсоров". О хранимых процедурах и
результирующих наборах см. "Вызов Хранимых Процедур".
После получения соединения (через объект database или объект Connection),
Вы можете работать с БД. В таблице резюмированы методы объектов database
и connection для работы с единственным соединением. Объект database
имеет и другие методы для обслуживания пула соединений, рассмотренные в разделе "Обслуживание
Пулов Соединений."
database и Connection
для Работы с Единственным СоединениемВ некоторых случаях может понадобиться, чтобы единственное соединение захватывало несколько клиентских запросов. То есть Вы сможете использовать одно соединение на нескольких страницах HTML.
Обычно вы используете свойства объекта client для информации,
захватывающего клиентские запросы. Однако значение свойства объекта client
не может быть объектом. Исходя из этого, Вы не можете сохранять пул соединений
БД в объекте client. Вместо этого Вы используете пул соединений,
хранимый в объекте project, обслуживая их так, как описано в данном
разделе. Если вы используете этот подход, Вам может понадобиться кодирование
пользовательской информации, по соображениям безопасности.
Будьте особенно осторожны при использовании такого подхода, поскольку сохранение соединения таким способом делает его недоступным для других пользователей. Если все соединения окажутся недоступны, новые запросы будут ожидать явного освобождения соединения или таймаута соединения. Это особенно проблематично для однопоточных библиотек БД. (Об установлении соединений так, что они будут запрашиваться, если не заняты в течение продолжительного времени, см. "Запрашивание Незанятого Соединения").
В следующем примере соединение и транзакция
захватывают несколько клиентских запросов. Код сохраняет соединение как свойство
объекта sharedConns, который сам является свойством объекта project.
Объект sharedConns не является предопределённым объектом JavaScript.
Он просто создан в данном примере и может иметь другое имя, по Вашему выбору.
Поскольку один пул используется всеми клиентами, Вы должны создавать объект sharedConns
и создавать и соединять сам пул на начальной странице приложения примерно таким
кодом:
project.sharedConns = new Object();
project.sharedConns.conns = new Object();
project.sharedConns.pool = new DbPool ("SYBASE", "sybaseserver",
"user", "password", "sybdb", 10, false);
Затем на первой клиентской странице, получающей доступ к пулу, следуйте такой стратегии:
// Генерируется уникальный индекс для обращения к данному клиенту, если он ещё
// не сгенерирован на другой странице.
if client.id == null {
client.id = ssjs_generateClientID();
}
// Для удобства устанавливается переменная для данного пула.
var clientPool = project.sharedConns.pool;
// Проверяется, соединён ли пул. Если нет, перенаправляется
// на специальную страницу для информирования пользователя.
project.lock();
if (!clientPool.connected()) {
delete project.sharedConns.pool;
project.unlock();
redirect("noconnection.htm");
}
project.unlock();
// Соединение получается из пула и сохраняется в объекте project.
project.sharedConns.conns[client.id] = clientPool.connection();
var clientConn = project.sharedConns.conns[client.id];
clientConn.beginTransaction();
cursor = clientConn.cursor("select * from customers", true");
// ... другие операции с БД ...
cursor.close();
}
Заметьте, что эта страница не выполняет откат или подтверждение транзакции.
Соединение остаётся открытым, и транзакция продолжается. (Транзакции
рассматриваются в разделе "Обслуживание Транзакций").
Вторая HTML-страница запрашивает соединение, базируясь на значении client.id,
и продолжает работать с БД так:
// Запрашивается соединение.
var clientConn = project.sharedConns.conns[client.id];
// ... Выполняются ещё какие-нибудь операции с БД ...
// Здесь, если операции с БД успешно прошли, okay устанавливается в 1.
// Если была ошибка при работе с БД, okay устанавливается в 0. В конце
// подтверждается или откатывается транзакция на основе этого значения.
if (okay)
clientConn.commitTransaction();
else
clientConn.rollbackTransaction();
// Соединение возвращается в пул.
clientConn.release();
// Избавляемся от значения свойства объекта. Оно Вам больше не нужно.
delete project.sharedConns.conns[client.id];
В этом примере объект sharedConns сохраняет единственный объект DbPool
и соединения для данного пула, которые используются в данный момент. Ситуация
может быть значительно сложнее. Если у Вас имеется фиксированный набор пулов БД,
Вы можете определить отдельный объект для хранения соединений каждого пула.
Если у вас имеется массив пулов и каждому пулу необходимы соединения,
захватывающие несколько запросов, Вам необходимо создать массив объектов, каждый
из которых сохраняет пул и массив его соединений. Как ответвление, вместо
немедленного перенаправления в том случае, если пул не соединён, клиентская
страница может сделать новую попытку установить соединение.
Если Вы используете ssjs_generateClientID и храните ID в объекте client,
Вам понадобится защита от вторжения и получения доступа к ID и, следовательно, к
закрытой информации.
В пуле, созданном объектом DbPool, соединений имеется фиксированное
количество соединений. Если в момент попытки доступа все соединения заняты, Ваше
приложение ожидает освобождения соединения в течение специфицированного периода
таймаута. Вы можете управлять периодом ожидания.
Предположим, Вы определили следующий пул из 3 соединений:
pool = new DbPool ("ORACLE", "myserv", "user", "password", "", 3);
Предположим далее, что три клиента одновременно получают доступ к приложению и каждый использует одно из трёх соединений. Четвёртый клиент теперь запрашивает соединение через следующий вызов:
myconnection = pool.connection();
Этот клиент обязан ждать, пока один из трёх клиентов не освободит соединение. В
данном случае, поскольку вызов connection не специфицирует таймаут,
клиент ждёт освобождения соединения неопределённо долго, а затем возвращает это
соединение.
Вы можете специфицировать различные периоды таймаута, задавая аргументы метода connection.
Второй аргумент метода connection это период таймаута в секундах.
Если Вы специфицируете таймаут 0, система ждёт бесконечно долго. Например,
следующий код ожидает соединения только 30 секунд перед таймаутом:
myconnection = pool.connection ("Name of Connection", 30);
Если в течение специфицированного периода соединение не освобождается, метод
возвращает null, и в сообщение об ошибке устанавливается сообщение о наименьшей
ошибке. Вы можете получить это сообщение, вызвав метод minorErrorMessage
объекта pool. Если Вы вызываете таймаут из connection,
Вам может понадобиться освободить соединение, отключив одно из уже установленных.
Дополнительно см. "Запрашивание Свободного Соединения".
Если Ваше приложение запрашивает соединение из объекта DbPool, оно
может не получить его. Доступные опции в этот момент зависят от архитектуры
Вашего приложения.
Если каждое соединение существует только в период существования отдельного клиентского запроса, недоступность соединений невозможна из-за того, что пользователь оставил приложение в бездействии на значительный период времени. Это может произойти только из-за того, что весь код страницы JavaScript не закончил выполняться. В этом случае Вы не должны пытаться разорвать используемое соединение, чтобы воспользоваться им. Если Вы разорвёте соединение в этот момент, Вы рискуете оставить этот поток выполнения в несоответствующем состоянии. Вместо этого Вы должны удостовериться, что Ваше приложение освобождает каждое соединение по мере завершения его использования. Если Вы не хотите ожидать соединения, Вы должны предоставить пользователю возможность выбора другого варианта.
Если, наоборот, соединение захватывает несколько клиентских запросов, Вы можете захотеть запросить свободные соединения. В этой ситуации соединение может освободиться, поскольку пользователь не завершил транзакцию. Например, предположим, что пользователь отправляет данные на первой странице приложения и эти данные начинают многостраничную транзакцию БД. Вместо отправки данных для продолжения транзакции на следующей странице, пользователь переходит на другой сайт и никогда не вернётся к данному приложению. По умолчанию соединение остаётся открытым и не может использоваться другими клиентами.
Вы можете вручную запросить соединение, зачистив его и освободив в пул БД. Чтобы сделать это, напишите функции типа нижеследующих:
Bucket: Определяет тип объекта (в данном примере - с названием bucket)
для содержания соединения и штампа времени.MarkBucket: Помечает объект bucket штампом текущего
времени.RetrieveConnections: Проходит по массиву соединений в поисках
объекта Connection, к которому не было доступа в течение
установленного лимита времени, и использует CleanBucket (описан
далее) для запрашивания этого объекта.CleanBucket: Закрывает курсоры (и возможные хранимые процедуры и
результирующие наборы), откатывает или подтверждает каждую открытую транзакцию
и возвращает соединение в пул.Ваше приложение может использовать эти функции так:
Bucket для
создания объекта bucket.MarkBucket
для обновления штампа времени.RetrieveConnection для поиска незанятых соединений,
закройте все открытые курсоры, подтвердите или откатите работающие транзакции
и верните незанятые соединения обратно в пул.Также на каждой странице, где Ваше приложение использует соединение, необходимо убедиться, что другой поток освободил соединение, до того как данная страница будет достигнута данным клиентом.
Функция bucket содержит соединение и штамп времени. Этот образец конструктора функции принимает соединение в качестве единственного параметра:
// Конструктор для Bucket
function Bucket(c)
{
this.connection = c;
this.lastModified = new Date();
}
Вы можете вызвать эту функцию для создания bucket для соединения, когда Вы получаете соединение из пула соединений. Вы можете добавить другие свойства для соединения bucket. Например, Ваше приложение может содержать курсор, который захватывает клиентские запросы. Тогда Вы можете использовать свойство для добавления курсора в bucket, так чтобы можно было закрыть открытый курсор при запрашивании соединения. Вы сохраняете курсор в bucket во время его создания, как видно из следующего оператора:
myBucket.openCursor =
myBucket.connection.cursor("select * from customer", true);
Функция MarkBucket принимает объект Bucket
в качестве параметра и устанавливает в поле lastModified текущее
время.
function MarkBucket(bucket)
{
bucket.lastModified = new Date();
}
Вызывайте MarkBucket на каждой странице приложения, которая
использует соединение, содержащееся в bucket. Это восстанавливает в lastModified
значение текущей даты и предотвращает появление незанятых соединений.
RetrieveConnections сканирует массив объектов Bucket,
ищет buckets соединения, штамп времени которых установлен ранее некоторого
определённого времени. Если соединение найдено, функция вызывает CleanBucket (описан
далее) для возвращения соединения в пул БД.
// Запрашиваются соединения, не занятые в течение специфицированного количества минут.
function RetrieveConnections(BucketArray, timeout)
{
var i;
var count = 0;
var now;
now = new Date();
// Этот цикл выполняется для каждого bucket в массиве.
for (i in BucketArray) {
// Вычисляется разница во времени между текущей/now и последней/last
// модифицированной датой. Эта разница выражается в миллисекундах.
// Если она больше значения timeout, вызывается функция зачистки.
if ((now - i.lastModified)/60000) > timeout) {
CleanBucket(i);
// Избавляется от bucket, поскольку он больше не используется.
delete i;
count = count + 1;
}
} return count;
}
После того как определено, что соединение должно быть
запрошено (с помощью функции RetrieveConnections), Вам понадобится
функция для зачистки подробностей соединения и возврата его обратно в пул базы
данных.
Данная функция-образец закрывает открытые курсоры, откатывает открытые
транзакции и освобождает соединение.
function CleanBucket(bucket)
{
bucket.openCursor.close();
bucket.connection.rollbackTransaction();
bucket.connection.release();
}
CleanBucket принимает, что данный bucket содержит открытый курсор
и его соединение имеет открытую транзакцию. Принимается также, что отсутствуют
хранимые процедуры и результирующие наборы. В Вашем приложении может
понадобиться и какая-нибудь другая проверка.
Следующий пример кода использует уже определённые функции для запрашивания соединений, к которым не обращались в течение 10 минут. Сначала создаётся совместно используемый массив соединений и пул БД с 5 соединениями:
if ( project.sharedConns == null ) {
project.sharedConns = new Object();
project.sharedConns.pool = new DbPool ("ORACLE", "mydb",
"user", "password", "", 5, false);
if ( project.sharedConns.pool.connected() ) {
project.sharedConns.connections = new Object();
}
else {
delete project.sharedConns;
}
}
Теперь используем следующий код для попытки получения соединения. После зачистки
пула генерируется клиентский ID, который затем используется как индекс в массиве
соединений. Далее пытаемся получить соединение. Если возникает таймаут, вызываем RetrieveConnections
для возвращения старого соединения в пул.
Если RetrieveConnections возвращает соединение в пул, пытаемся
получить соединение вновь. Если всё ещё не можем получить соединение,
выполняется перенаправление на другую страницу с информацией, что свободных
соединений нет. Если запрашивается соединение, сохраняем его в новом bucket
соединения и сохраняем этот bucket соединения в совместно используемом массиве
соединений.
if ( project.sharedConns != null ) {
var pool = project.sharedConns.pool;
// Этот код запускается, только если пул уже соединён.
// Если нет, возможно, Вам нужен код для соединения.
if ( pool.connected() == true ) {
// Генерируется клиентский ID.
client.id = ssjs_generateClientID();
// Попытка получить соединение.
var connection = pool.connection("my connection", 30);
// Если соединение null, тогда ничего не будет доступно // в течение специфицированного лимита времени. Пытаемся запросить старые соединения.
if (connection == null) {
// Запрашиваются соединения, не используемые в течение последних 10 минут.
var count = RetrieveConnections(project.sharedConns.connections, 10);
// Если count не равен 0, делаем какое-нибудь соединение доступным.
if (count != 0){
connection = pool.connection("my connection", 30);
// Если connection всё ещё null, отказываемся.
if (connection == null)
redirect("nofreeconnections.htm");
}
else {
// Отказываемся.
redirect("nofreeconnections.htm");
}}
// Если Вы не дошли досюда, Вы получили соединение и можете продолжить работу.
// Поместите это connection в новый bucket, стартуйте транзакцию,
// получайте курсор, сохраняйте его в bucket и продолжайте работу.
project.sharedConns.connections[client.id] = new Bucket(connection);
connection.beginTransaction();
project.sharedConns.connections[client.id].cursor =
connection.cursor("select * from customer", true);
// Помечаем bucket соединения как использованный.
MarkBucket(project.sharedConns.connections[client.id]);
// Операторы Базы Данных.
...
}
На следующей странице многостраничной транзакции выполняются операции БД по этому соединению. После последней операции БД по соединению помечается bucket соединения:
var Bucket = project.sharedConns.connections[client.id];
if ( Bucket == null) {
// Повторное соединение.
}
else {
// Взаимодействие с БД.
...
// Последняя операция БД на странице.
row = Bucket.cursor.next();
row.customerid = 666;
Bucket.openCursor.insertRow("customer");
// Помечается bucket соединения как использованный на данной странице.
MarkBucket(Bucket);
}
Дата последнего обновления: 29 сентября 1999 г.
© Copyright © 1999 Sun Microsystems, Inc. Некоторая часть Copyright © 1999 Netscape Communications Corp. Все Права Зарезервированы.
| Содержание сайта (выборка) |
| Apache |
| Протоколы TCP/IP (принципы, протоколы и архитектура) |
| PHP, PELR, JSP |
| PHP |
| JavaServer Pages (JSP) |
| Базы данных |
| Основы mysql |
| СУБД INFORMIX |
| СУБД POSTGRES |
| Основы проектирования реляционных баз данных |
| Паскаль, C, C++, C# |
| GCC (примеры) |
| FAQ Валентинa Озеровa DELPHI |
| C |