Рассылка закрыта
При закрытии подписчики были переданы в рассылку "Вопросы и ответы по MS SQL Server" на которую и рекомендуем вам подписаться.
Вы можете найти рассылки сходной тематики в Каталоге рассылок.
MS SQL Server - дело тонкое...
Информационный Канал Subscribe.Ru |
#131<< #132 |
СОДЕРЖАНИЕ
SQL транзакции и ASP Автор: Вадим Ковальчученко
Возьмем некий объект - человека, бухгалтерскую проводку, звездное небо над головой. В грамотно спланированной базе данных характеристики объекта данных распределены по нескольким таблицам. Всякий раз, когда мы изменяем статус объекта (удаляем его или вставляем новый), мы должны изменить несколько таблиц за одну операцию. Аналогично, если данные в таблице - это результаты вычислений, зависящих от значений в других таблицах, то, изменяя данные в таблицах-аргументах, необходимо поменять значения и в результирующей таблице. Все идет хорошо до тех пор, пока запрос на выполнение изменений данных в одной из таблиц не сможет быть выполнен. Причины этого могут быть самые разные: несоответствие ограничениям, наложенным на таблицу, попытка вставить дублирующие данные, нестандартные значения, введенные пользователем и проскользнувшие через все проверки, логические ошибки при вычислениях, деление на ноль и т.д. Наконец, сервер может просто перестать работать во время выполнения серии запросов. Все это может привести к разбалансированию данных, и как следствие - к лишним или исчезнувшим деньгам на счетах клиентов, ожившим мертвецам и фантомам и всемирной катастрофе в финале. Для себя я определяю транзакцию как несколько SQL-запросов, которые сервер должен выполнить последовательно, при этом все запросы должны быть выполнены успешно. Если хотя бы один из запросов не будет выполнен, база данных останется без изменений. Транзакция обеспечивает неделимость блока операции: или все запросы будут выполнены, или ни один из них не будет зафиксирован в базе данных. Для клиентских приложений, работающих с SQL-сервером напрямую, начать транзакцию несложно. Устанавливая соединение, приложение выполняет команду BEGIN TRAN и выполняет все необходимые запросы. В конце блока команд приложение посылает команду COMMIT TRAN, и если все запросы и вычисления были выполнены успешно, то транзакция фиксируется. Однако для интернет-приложений, работающих с SQL-сервером через web-сервер, ситуация сложнее. По умолчанию каждый запрос выполняется как отдельная единичная транзакция, которая начинается и тут же завершается. Кроме того, web-приложение не может послать SQL-серверу ничего, кроме непосредственно SQL-запроса (SELECT, INSERT, UPDATE и т.д.). Что же делать? Как реализовать логику приложения и в то же время иметь возможность возврата к предыдущему состоянию? ADO (ActiveX Document Object) предоставляет два способа начать транзакцию внутри исполняемого скрипта ASP. Первый способ - это объявить в начале скрипта директиву
<%@ TRANSACTION=Required %> В этом случае ВСЕ выражения скрипта рассматриваются в теле единичной транзакции. Вроде бы это то, что нам нужно. Однако отследить, какое же действие вызвало нарушение транзакции, здесь чрезвычайно трудно. Все, что можно сделать, это только определить процедуру сообщения для пользователя, которая обрабатывает скрипт при появлении события фиксирования или отката транзакции (OnTransactionCommit и OnTransactionAbort соответственно). Второй способ - объявить начало транзакции непосредственно в скрипте, перехватить коды ошибок выполнения транзакций и на основе их значений определить необходимость фиксирования или отката. ASP-код:
Приведенный выше код я записал в Code Template своего любимого редактора HomeSite, вставляю его в код приложения и модифицирую как нужно. Рассмотрим код транзакции по частям. 1. Подготовка.
' Prepare Transaction Statements ' Statement1 stmt_1 = " SELECT field1, field2 " &_ " FROM table AS alias " &_ " WHERE field1 = field2 " 'trc(stmt_1) ' Statement2 stmt_2 = " SELECT field1, field2 " &_ " FROM table AS alias " &_ " WHERE field1 = field2 " 'trc(stmt_2) ' Statement3 stmt_3 = " SELECT field1, field2 " &_ " FROM table AS alias " &_ " WHERE field1 = field2 " 'trc(stmt_3) ' Statement4 stmt_4 = " SELECT field1, field2 " &_ " FROM table AS alias " &_ " WHERE field1 = field2 " 'trc(stmt_4) ' Statement5 stmt_5 = " SELECT field1, field2 " &_ " FROM table AS alias " &_ " WHERE field1 = field2 " 'trc(stmt_5) В начале мы подготавливаем все SQL-запросы, которые будут участвовать в транзакции. Если какой-то запрос формируется на основе значений, которые будут получены в результате выполнения предыдущих запросов, то его придется включить в тело транзакции. Я помещаю SQL-запросы до транзакции, так как их проще оттрассировать, пока еще ничего не началось. Кстати, о трассировке. Под запросом расположен вызов моей простенькой функции для распечатки ее аргументов. В данном случае аргументом будет текст запроса. Определение функции записано в function.asp (подключаемом модуле).
Function trc(var) Response.Write "<p><em>var=" & var & "</em></p>" End function
2. Начало транзакции.
X=cn.BeginTrans Это и есть точка начала транзакции, где cn - имя объекта (типа ADODB.Connection). 3. Выполнение запросов Это непосредственное выполнение запросов в теле транзакции.
On Error Resume Next cn.Execute (stmt_1) if Not (Cint(Err.Number) = 0) then Success1=False else Success1=True On Error Resume Next cn.Execute (stmt_2) if Not (Cint(Err.Number) = 0) then Success2=False else Success2=True On Error Resume Next cn.Execute (stmt_3) if Not (Cint(Err.Number) = 0) then Success3=False else Success3=True On Error Resume Next cn.Execute (stmt_4) if Not (Cint(Err.Number) = 0) then Success4=False else Success4=True On Error Resume Next cn.Execute (stmt_5) if Not (Cint(Err.Number) = 0) then Success5=False else Success5=True On Error GoTo 0 Перед тем как выполнять запрос, я устанавливаю режим обработки ошибок с помощью выражения On Error Resume Next. Во время отлаживания скрипта можно было бы обойтись и без него, но ведь скрипт будет работать в реальном приложении, поэтому негоже (и даже недопустимо!) показывать пользователю SQL-ошибки. Команда cn.Execute (stmt_1) пытается исполнить запрос. Здесь cn - это идентификатор объекта типа ADODB.Connection, Execute - метод (команда), исполняющая запрос, stmt_1 - строковая переменная, содержащая тело запроса. Далее я оцениваю успешность выполнения запроса. Глобальная переменная Err.Number содержит код ошибки. Выполняю ее приведение к целому типу и сравниваю с нулем. Если код ошибки НЕ равен нулю, запрос НЕ был выполнен, тогда флаг ошибки с номером запроса становится равным FALSE, иначе TRUE. Обратите внимание, что для правильной обработки ошибки необходимо выполнять выражение On Error Resume Next перед каждым вызовом метода Execute. В конце выполнения транзакции я отключаю обработку ошибок, выполняя выражение On Error GoTo 0. По не вполне понятным для меня причинам, если попытаться оценить код ошибки на РАВЕНСТВО с нулем, код перестает работать и флаги выставляются в значение FALSE, вне зависимости от правильности выполнения запроса. 4. Первичная трассировка.
' trc("Success1="&Success1) ' trc("Success2="&Success2) ' trc("Success3="&Success3) ' trc("Success4="&Success4) ' trc("Success5="&Success5) Это блок трассировки флагов выполнения запросов. Вызовы функций закомментированы, но не убраны из окончательной версии скрипта. Они пригодятся в дальнейшем при отладке скрипта. 5. Завершение транзакции.
If Cbool ((Success1=True) AND (Success2=True) AND (Success3=True) AND (Success4=True) AND (Success5=True) ) then cn.CommitTrans bool_Trans = True Else cn.RollBackTrans bool_Trans = False End if ' End transaction С помощью логического оператора AND я определяю, все ли флаги выполнения запросов установлены в значение TRUE. Если все - транзакцию можно фиксировать командой(методом) CommitTrans, а также выставить общий флаг успешного завершения транзакции - bool_Trans = True. В противном случае транзакция откатывается при помощи метода RollBackTrans, а флаг выставляется в значение bool_Trans = False. Флаг выставляется для того, чтобы позже выдать сообщение об ошибке в контексте web-страницы. Можно будет, конечно, СНОВА оценить все флаги запросов, но зачем делать дополнительные вычисления? Получив сообщение об откате транзакции, я раскомментирую блок первичной трассировки флагов запросов и выполняю код снова:
trc("Success1="&Success1) trc("Success2="&Success2) trc("Success3="&Success3) trc("Success4="&Success4) trc("Success5="&Success5) Так становится ясно, какой запрос не получается выполнить. Допустим, что флаг Success3 = FALSE. Перехожу к строке запроса N3 и раскомментирую трассировку:
trc(stmt_3) Полученную строку копирую в браузере и вставляю в SQL Query Analizer, который сразу выдает информацию о характере ошибки (Syntax Error, несоответствующие права доступа и т.д.). Добившись выполнения запроса в Query Analizer, переношу запрос в скрипт, заменив константы на переменные, и пробую выполнить транзакцию снова. Если флаг ошибки тот же, перехожу к строке выполнения запроса:
On Error Resume Next cn.Execute (stmt_3) if Not (Cint(Err.Number) = 0) then Success3=False else Success3=True Вставляю
On Error GoTo 0 перед
cn.Execute (stmt_3) отключая тем самым режим обработки ошибок. В браузере появляются код и описание ASP- и SQL-ошибки (неправильное использование объекта Сonnection, отсутствие прав на изменение объектов базы данных и т.д.). Добившись выполнения запроса, комментирую трассировки и команду завершения обработки ошибок и снова пытаюсь выполнить транзакцию. Если получена новая ошибка, повторяю процесс отладки снова. Последний метод отладки позволяет получить коды ошибок и тестировать приложение, даже если у вас нет при себе среды разработчика и копии базы данных для тестирования. По сравнению с методом объявления директивы @ TRANSACTION, явное объявление транзакции обладает двумя не оспоримыми преимуществами - легкостью отладки именно SQL-запросов и возможностью тестировать web-приложение в реальной базе данных без фиксирования изменений. Ничто ведь не мешает НЕ фиксировать транзакцию ВООБЩЕ, а просто откатывать ее во всех случаях и выставлять флаги завершения. Можно даже получать результаты запросов на вставку (удаление) данных, НЕ фиксируя их фактически. Для этого достаточно выполнить соответствующий запрос на выборку данных ДО отката транзакции. Если вся логика приложения перенесена на SQL-сервер, то хорошим решением считаются триггеры с каскадным срабатыванием. Впрочем, тогда можно и обычные транзакции применить в расширенных процедурах. Однако для web-мастера это часто неприемлемо. Сторонний разработчик часто не имеет прав на создание таких объектов базы данных, как триггеры и расширенные процедуры. Все, что он имеет, - это право на изменение скриптов приложения и выкладывания их на FTP-сервер. Что делать тем, кто не имеет доступа на SQL-сервер с обработкой транзакций? Посочувствуем им, жизнь их сильно затруднена. Создать полноценное устойчивое приложение без транзакций чрезвычайно сложно. Что делать тем, кто пишет на PHP? Не знаю. Насколько мне известно, PHP не имеет синтаксиса и методов для явного или неявного объявления транзакций. Переходите на ASP. Автор готов принять все возмущенные отклики и рецензии на эту статью по адресу http://lord.o2.kz/message.asp
С уважением, Вадим Ковальчученко - автор ненаписанных и нигде не опубликованных работ по связкам SQL-ASP-PHP. Работает консультантом информационных систем консалтинговой компании Deloitte & Touche в Алма-Ате. Его портфолио web-мастера и разработчика находится по адресу http://lord.o2.kz Безопасность Microsoft SQL Server 2000 (ПРОДОЛЖЕНИЕ) По материалам статьи Richard Waymire и Ben Thomas: Microsoft SQL Server 2000 Security
1. Введение Как уже отмечалось выше в этой статье, сертификация по уровню безопасности C2 подразумевает наличие у SQL Server 2000 встроенной, развитой системы аудита, которая состоит из нескольких компонент, описанных ниже. Совместно, эти компоненты позволяют отслеживать попытки применения любых прав в рамках SQL Server 2000.
SQL trace - это серверные компоненты обеспечения аудита. Аудит был добавлен к аналогичному механизму SQL Server 7.0,
предоставляющему информацию об эффективности SQL Server. Информация об эффективности по прежнему доступна, но в
SQL Server 2000 этот интерфейс был полностью пересмотрен. Все соответствующие хранимые процедуры SQL Server 7.0
были изменены. SQL Profiler является утилитой с графическим интерфейсом, которая позволяет просматривать файлы трассировки аудита безопасности, и совершать с этими файлами, посредством пользовательского интерфейса, такие операции, как: поиск по файлу, сохранение трассы в файл или в таблицу, а также можно создавать и настраивать описатель трассы. По сути, SQL Profiler является клиентом SQL trace, и не обязательно иметь запущенным SQL Profiler, чтобы аудит безопасности был работоспособен, он работает автономно от SQL Profiler. Режим аудита C2 предопределяет набор отслеживаемых событий (все события безопасности), которые фиксируют данные (всё, что несёт информацию об этих событиях), и другие установленные параметры настройки. Каждый из возможных режимов описан в SQL Server Books Online. 2.6. Исключение SQLAgentCmdExec Proxy Account
В SQL Server 2000 учетная записи SQLAgentCmdExec не создаётся, в отличие от SQL Server 7.0 и более ранних версий,
где эта учётная запись применялась для заданий по расписанию SQL Server Agent, запускаемых из контекста безопасности
логина, не имеющего привилегий системного администратора, для получения доступа к ресурсам Windows. Это была
локальная учетная запись пользователя Windows NT 4.0 и Windows 2000, созданная при установке SQL Server. 2.7. Расширение набора серверных ролей В SQL Server 2000 был расширен набор фиксированных серверных ролей. Для получения более полной информации о фиксированных серверных ролях, см. раздел "Предопределенные роли", который будет ниже в этой статье. BulkAdmin - это новая роль SQL Server 2000. Логины, включенные в эту роль, могут выполнять команду BULK INSERT. Пользователи, являющиеся членами этой группы, будут иметь возможность загружать данные из любого файла в сети и с любого компьютера, находясь в контексте безопасности учетной записи запускающей сервис MSSQLServer. Следует очень ответственно относиться к включению логинов в эту серверную роль. Для того, что бы члены этой роли могли выполнить команду BULK INSERT в какую-либо таблицу, им требуется иметь право на INSERT для этой таблицы. Членство в этой фиксированной серверной роли предоставляет права только на исполнение инструкции BULK INSERT и на обращение к файлам в течении исполнения команды. Роль SecurityAdmin даёт право на изменение паролей логинов в режиме аутентификации SQL Server Authentication. Исключение из этого составляют только пароли членов фиксированной серверной роли sysadmin, которые не могут быть сброшены. Роль ServerAdmin была расширена для обеспечения возможности управления серверными сообщениями. Членство в этой роли позволяет теперь логину исполнять хранимые процедуры: sp_addmessage, sp_dropmessage и sp_altermessage. ПРОДОЛЖЕНИЕ СЛЕДУЕТ Отечественные статьи
Основные концепции и
подходы при создании контекстно-поисковых систем на основе реляционных баз
данных
Новые технические статьи Microsoft
PRB:
SQL Server Only Uses Two GB of Memory Even Though the AWE Option is Enabled
Logins, Users, and Roles - Getting Started ОБНОВЛЕНИЕ: Презентация "Безопасность Microsoft SQL Server 2000" Обновлена презентация доклада Дмитрия Артемова на конференции Microsoft: Платформа 2003 Безопасность Microsoft SQL Server 2000 (ZIP - 730K.)
Самые популярные темы недели
Междумордие
Какой
SET вкл./откл. заглавные буквы в названиях обьектов
|
#131<< #132 |
http://subscribe.ru/
E-mail: ask@subscribe.ru |
Отписаться
Убрать рекламу |
В избранное | ||