Куперс

Бухучет и анализ

Основные способы трансформации рыночных отношений во внутрифирменные

Фундаментальная трансформация рыночных отношений во внутрифирменные

Концентрация и централизация производства и капитала и процесс укрупнения хозяйствующей единицы. Ограниченность ресурсов и действие закона возрастающей затратности и убывающей доходности. Роль инфраструктуры, информации и новых товаров.

Увеличение затрат на трансакции в результате увеличения количества экономических субъектов, размеров экономической системы и информационного потока (количества связей в рамках хозяйственной системы). Выбор предпринимателя между рыночными трансакциями, контрактной системой и внутрифирменной иерархией.
Выше нами достаточно подробно были рассмотрены явления концентрации и централизации капитала. Они предстали перед нами в качестве объективных характеристик процесса развития капитала. У концентрации и централизации капитала и производства фактически одна форма их конкретного проявления в экономических процессах — укрупнение хозяйствующих единиц. Этот процесс не только реально идет, но он к тому же подробно количественно описан. Есть несколько корректных, признаваемых большинством исследователей показателей, которые дают возможность видеть этот процесс в динамике.
Приведем данные по крупнейшим фирмам (компаниям, предприятиям) мира, занятым в реальном секторе экономики (табл. 6).
Аналогичные процессы протекают и в других сферах деятельности (финансы, торговля, страховое дело, банковское дело и т. д.).
Концентрация и централизация капитала и производства, укрупнение размеров хозяйствующих единиц — это первые причины, обуславливающие процесс фундаментальной трансформации.
Другими причинами, сокращающими сферу господства рыночной организации, по нашему мнению, являются: 1) действие объективной тенденции возрастания затратности и убывания доходности в результате ограниченности ресурсов, 2) возрастание роли инфраструктуры, 3) информации, 4) новых товаров, 5) увеличение затрат на трансакции в результате роста количества экономических субъектов, размеров экономической системы и информационного потока.
Таблица б
Крупнейшие фирмы США и России (1970 —2008 гг.)
Продолжение табл. 6
* — номер в мировом рейтинге крупнейших фирм.

http: //money.cnn.com/magazines /fortune/fortune500/2008/
Рассмотрим указанные причины подробнее.
Действие объективной тенденции возрастания затратности и убывания доходности в результате ограниченности ресурсов. Данная тенденция может не требовать в целом более крупных хозяйствующих субъектов, так как только им под силу становится использовать возрастающую массу предметов труда, которые с течением времени обходятся человечеству дороже (переход к более бедным месторождениям и разработка ресурсов, находящихся дальше от мест традиционного использования).
Возрастание роли инфраструктуры. Инфраструктурные объекты — наиболее капиталоемкие, требующие к тому же значительных текущих затрат. Их сооружение не представляется возможным в рамках только рыночной экономической организации без использования контрактной системы и все более крупных фирм. Обслуживание инфраструктурных объектов под силу только сверхкрупным компаниям с развитой внутрифирменной иерархией (большинство из них являются естественными монополиями, так как инфраструктура часто служит объектом естественных монополий (трубопроводы, транспортные системы, линии электропередач и проч.)).

Возрастание роли информации. Информационные системы — это часть инфраструктуры, поэтому все, что справедливо применительно к инфраструктуре, справедливо и применительно к ним. Здесь самостоятельным аспектом является именно возрастание роли информации. Поэтому вполне уместно говорить и об информационном обществе, и об информационных технологиях, и т. д.
Роль новых товаров. Разработка, подготовка к производству, массовое производство товаров с принципиально новыми свойствами вряд ли под силу мелкому и среднему капиталу. Это удел крупных и сверхкрупных компаний (есть даже такая монополистическая политика — «быть второй», т. е. быть за спиной некрупной компании — инноватора и успеть вовремя перехватить у нее производство нового товара). Само же производство новых товаров также требует и контрактных трансакций, и отношений внутрифирменной иерархии.
Увеличение затрат на трансакции в результате роста количества экономических субъектов, размеров экономической системы и информационного потока. Положения, связанные с ростом количества экономических субъектов, размеров экономической системы и информационного потока, как нам представляется, уже нашли свое доказательство на страницах данной работы. Все они в конечном итоге ведут к росту затрат на совершение сделок (трансакций). Мы не можем абстрагироваться от такого рода издержек, и поэтому неправомерно вести разговор о бесплатности рыночных трансакций. В данном случае нельзя говорить только о рыночной экономической организации. Мы должны вести речь о контракт
ной системе и внутрифирменной иерархии. Все это в результате и подрывает монополию рыночной экономической организации.
Теперь наш предприниматель стоит перед непростым выбором: или рынок с его бесплатностью трансакций, но высокой степенью неопределенности, или контрактная система с незначительной мерой неопределенности и риска невыполнения контракта одной из сторон, но с достаточно высокими затратами на реализацию трансакций, или внутрифирменная иерархия с нерыночным типом организации и господством административных отношений, или какие-то комбинации из представленных форм экономической организации, или нерыночные отношения в рамках рыночных систем.
Фундаментальная трансформация рыночных отношений во внутрифирменные происходит в двух основных формах, которые мы и будем рассматривать в двух последующих частях данного исследования.

Концепция транзакции лежит в основе реляционной парадигмы. Транзакция состоит из одной или нескольких DML команд и следующей командой или ROLLBACK или COMMIT. Возможно использовать команду SAVEPOINT для определённого управления внутри транзакции. Перед рассмотрением синтаксиса необходимо рассмотреть концепцию транзакций. Связанная с этой темой это тема согласованного чтения; это реализуется автоматически на уровне Oracle сервера, но некоторые программисты могут управлять им с помощью SELECT команд.

Транзакции БД

Механизм Oracle для обеспечения транзакционной целостности основан на сочетании сегментов отмены изменений и файла журнала логов: этот механизм бесспорно лучший из всех созданных на сегодняшний день и полностью удовлетворяет международным стандартам обработки данных. Производители других БД реализуют стандарт своими собственными другими способами. Вкратец, любая реляционная база данных должна удовлетворять тесту ACID: должны быть гарантированы атомарность (A – atomicity), согласованность (C – consistency), изолированность (I – isolation) и долговечность (D – durability).

Aтомарность

Принцип атомарности гласит что либо все части транзакции должны быть выполнены успешны либо ни одна из них. Например если бизнес-аналитик утвердил правило что при смене зарплаты сотрудника обязательно изменяется уровень сотрудника то ваша атомарная транзакция будет сосять из двух частей. БД должна гарантировать что будут применены либо оба изменения, либо ни одного. Если только одно изменения будет успешно то у вас появится сотрудник чья зарплата несовместима с его уровнем: повреждение данных в терминах бизнеса. Если что-нибудь (вообще что-нибудь) пошло не так до подтверждения транзакции, БД должна гарантировать что вся работа совершённая до этого момента от начала транзакции будет отменена: это должно работать автоматически. Несмотря на то что атомарность транзакции звучит как что-то маленькое – транзакции могут быть долгими и очень важными. Рассмотрим другой пример, в бухгалтерской книге не может быть данных на пол-месяца Августа и пол-месяца Сентября: закрытие месяца с точки зрения бизнеса одна атомарная транзакция, которая может обрабатывать миллионы строк и тысячи таблицы и работать несколько часов (или отменяться если что-то пошло не так). Отмена транзакции может быть ручной (выполнив команду ROLLBACK) но она должна быть автоматической и неотменяемой в случае ошибки.

Согласованность

Принцип согласованности данных гласит что результат запроса должен быть согласован с состояним базы данных на момент старта работы запроса. Преставим простой запрос которые считает среднее значение столбца в таблице. Если таблица большая, это займёт достаточно долгое время для прохода по всем строкам таблицы. Если другие пользователи в это время обновляют данные пока запрос выполняется, должен ли запрос брать новые значения или старые? Должен ли результат запроса учитывать строки которые были добавлены или не учитывать строки которые были удалены? Принцип согласованности требует чтобы БД гарантировала что любые изменения после старта запроса не были видны для этого запроса; запрос должен вернуть среднее значение столбца на момент когда запрос был запущен, вне зависимости от того как долго длился запрос и какие изменения были над данными. Оракл гарантирует что если запрос выполнен успешно – результат будет согласованным. Как бы там ни было, если администратор базы данных не настроил базу данных соотвествующим образом, запрос может не выполнится: возникнет знаменитая ошибка “ORA-1555 snapshot too old”. Раньше было очень сложно решить такие ошибки, но в последних версиях администратор легко может решать эти ситуации.

Изолированность

Принцип изолированности гласит что незаконченная (неподтверждённая транзакция) должна быть невидима для остального мира. Пока транзакция в процессе только сессия которая выполняет эту транзакцию видит зименения. Все остальные сессии должны видеть неизменённые данные. Почему так? Во первых, транзакция может целиком не выполниться до конца (помним про принцип атомарности и согласованности) и поэтому никто не должен видеть изменения которые могут быть отменены. Во вторых во время действия транзакции данные (в терминах бизнеса) бессвязные: для нашего примера обновления зарплаты будет существовать промежуток времени когда зарплата изменена, а уровень ещё нет. Изолированность транзакций требудет чтобы база данных прятала текущие транзакции от других пользователей: они будут видеть данные до изменений пока транзакция выполняется, а затем сразу будут видеть все изменения как согласованный набор данных. Oracle гарантирует изолированность транзакций: нет способа для сессии (отличной от той что делает изменения) увидеть неподтверждённые данные. Чтение неподтверждённых данных (известное как грязное чтение dirty read) не позволяется Oracle (несмотря на то что некоторые другие БД позволяют).

Долговечность

Принцип долговечности указывает на то, что если транзакция успешно завершена, то должно быть невозможно потерять эти данные. Во время работы транзакции принцип изолированности требует чтобы никто кроме сессии выполняющей изменения не видел их. Но как только транзакция успешно завершила работу, изменения должны стать доступны для всех и база данных должна гарантировать что они не будут потеряны. Oracle выполняет это требование путём записывания всех векторов изменений в файлы логов перед тем как изменения подтверждены. Применив этот логи изменений к резервным копиям, всегда возможно повторить любые изменения которые были выполнены в момент остановки или повреждения базы данных. Конечно данные могут быть потеряны из-за ошибок пользователей, таких как выполнение неверных DML запросов или удаление таблиц. Но с точки зрения Oracle и администратора базы данных, такие события тоже транзакции: согласно принципу долговечности их нельзя отменить.

Выполнение SQL запросов

Весь язык SQL состоит из около дюжины команд. Сейчас нас интересуют команды: SELECT, INSERT, UPDATE и DELETE.

Выполнение команды SELECT

Команда SELECT получает данные. Выполнение команды SELECT это процесс состоящий из нескольких этапов: серверный процесс выполняющий запрос проверит существует ли необходимые блоки данных в памяти, в буфере кэша. Если они там, то выполнение может продолжаться, иначе серверный процесс должен найти данные на диске и скопировать их в буфер кэша.

EXAM TIP

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

Как это связано с тестом ACID? Для согласованности, если запрос обнаружит что блок данных изменился с момента старта запроса, серверный процесс найдёт сегмента отката (отмены изменений или сегмент undo) соответствующий этому изменению, найдёт старую версию данных и (для текущего запроса) отменит изменение. Таким образом изменения которые произошли после начала запроса будут не видны. Похожим образом гарантируется изолированность транзакций, несмотря на то что изолированность основана и на подтверждённых изменениях. Честно говоря, если данные необходимые для отмены изменений не существуют больше в сегменте отката – этот механизм не сработает. Отсюда и следует ошибка “snapshot too old”.

На рисунке 8-4 показан путь обработки запроса SELECT

Шаг 1 это передача пользовательского запроса от пользовательского процесса к серверному. Серверный процесс просматривает буфер кэш на наличие нужных блоков и если они в буфере то переходит к шагу4. Если нет то шаг 2 находит блоки в файлах данных и шаг 3 копирует данные в буфер. Шаг 4 передает данные сервеному процессу где может быть дополнительная обработка перед тем как шаг 5 вернёт результат запроса пользовательскому процессу.

Выполнение команды UPDATE

Для любой команды DML необходимо работать с блоками данных и блоками отката (undo blocks), а также создавать лог изменений (redo): A,C и I принципы теста ACIDS требуют создания данных отката; D требует создание данных повтора изменений (redo).

Exam tip

Undo не противоположна redo! Redo защищает все изменения блоков, вне зависимости это изменения блока таблицы, индекса или сегмента отката. Для redo — undo сегмент такой же сегмент как таблцы и все изменения должны быть долговечны (durable)

Первый шаг при выполнении DML команды такой же как и при выполнении команды SELECT: необходимые блоки должны быть найдены в кэф буфере или скопированы с файлов данных в буфер. Единственное отличие это то что дополнительно требуется пустой (или устаревший – expired) блок отката. Затем выполнение становится сложнее чем при команде SELECT.

Вначале блокировки должны быть указаны для все строк и соотвествующих индексов которые будут задействованы в процессе.

Потом создаются данные redo: серверный процесс записывае в логи буфера вектора изменений которые будут применены к данным. Redo данные создаются и для изменений блока данных и для изменений блока отката: если столбец в строке будет обновлен то rowid и новое значение записывается в буфер лога (изменение которое будет применено к блоку таблицы), а также старое значение столбца (изменение для блока отката). Если столбец это часть ключа индекса – то изменения в индексе тоже будут записаны в буфер лога, вместе с изменениями которые будут сделаны в блоке отката для защиты изменений индекса.

После того как все redo данные созданы, обновляются данные в буфер кэше: блок данных обновляется на новую версию с измененным столбцом, а старая версия записывается в блок отката. С этого момента до подтверждения транзакции, все запросы от других сессий обращающиеся к этой строке будут перенаправлены на блок отката. Только сессия которая делает UPDATE будет видеть актуальную версию строки а блоке таблицы. Такой же принцип применяется для всех связанных индексов.

Выполнение команд INSERT и DELETE

Концептуально INSERT и DELETE управляются в той же манере как и UPDATE. Вначале происходит поиск нужных блоков в буфере и если их нет то они копируются в память.

Redo создается точно так же: все вектора изменений которые будут применены к данным и блокам отката вначале записываются в буфер лога. Для команды INSERT вектор изменений блока таблицы (и возможно блоков индекса) это байты которые составляют новую строку (и возможно новый ключ индекса). Вектор для блока отката это rowid новой строки. Для команды DELETE вектор для блока отката это вся строка.

Ключевым отличием между командами INSERT и UPDATE является количество данных для отката. Когда строка добавляется единственными данными для отката будет запись rowid в блок отката, потому что для отмены команды INSERT единственная информация нужная Oracle это rowid строки и может быть создана команда

delete from table_name where rowid=rowd_id_of_new_row;

Выполнение этой команды отменит изменение.

Для команды DELETE вся строка (которая может быть несколько килобайт) должна быть записана в блок undo, и тогда удаление может быть отменено при необходимости путём генерации запроса который заново добавил полностью строку в таблицу.

Начало и конец транзакции

Сессия начинает транзакция в момент когда она выполняет любую DML команду. Транзакция продолжается сколько угодно следующих DML команд пока сессия не выполнит команду ROLLBACK или COMMIT. Только подтвеждённые изменения станут гарантированными и будут доступны для других сессий. Невозможно начать транзакцию внутри транзакции. Стандарт SQL не разрешает пользователям начать транзакцию, а затем начать новую перед завершение первой. Это можно сделать используя PL/SQL (язык Oracle третьего поколеняи), но не стандартным SQL.

Командами управления транзакциями являются команды COMMIT, ROLLBACK и SAVEPOINT. Также могут возникнуть другие обстоятельства помимо явного вызовая команды COMMIT или ROLLBACK которые немедленно прекращают транзакцию

  • Выполнение DDL или DCL команды
  • Завершение польховательского процесса (к примеру пользователь вышел из программы SQL *Plus или SQL Developer)
  • Клиентская сессия «умерла»
  • Проблемы в системе

Если пользователь выполняет DDL команду (CREATE, ALTER или DROP) иди DCL команду (GRANT или REVOKE) то активная транзакция (если она сущесвтует) будет подтверждена. Так происходит потому что команды DDL и DCL сами являются транзакциями. Так как в SQL невозможно создать вложенные транзакции, если у пользователя уже выполнялась какая либо транзакция, все команды пользователя будут подтверждены вместе с командой DDL или DCL.

Если вы начали транзакцию выполнив DML запроса, а затем закрыли программу без явного указания COMMIT или ROLLBACK до выхода, транзакция будет прекращена – но прекращена с подтверждением или отменой целиком зависит от программы. У разных программ может быть разное поведение в зависимости от того как вы закончили работу в программе. Например в Windows обычно можно выйти из программы выбрав пункты меню File – Exit или нажав на крестик в правом верхнем углу. Программист мог обработать по разному эти способы завершения и в первом случае указать COMMIT, а во втором ROLLBACK. В любом случае это будет контролируемый выход.

Если клиентская сессия отказывает по какой-либо причине – база данных всагда отменит транзакцию. Такие отказы могут быть по разным причинам: пользовательский процесс мог быть «убит» диспетчером, проблемы с сетью или поломка пользовательской машины. В любом случае не было явно указана команда COMMIT или ROLLBACK и БД нужно решить что случилось. В таком случае сессия «убивается» и активная транзакция отменяется. И точно так-же база данных ведёт в себя в случае проблем на стороне сервера. Если база данных была закрыта аварийно то при следующем старте все транзакции которые были начаты но явно не завершены будут отменены.

Управление транзакциями: COMMIT, ROLLBACK, SAVEPOINT и SELECT FOR UPDATE

Oracle начинает транзакцию в момент запуска первой DML команды. Транзакция длится до вызова команды ROLLBACK или COMMIT. Команда SAVEPOINT не является частью SQL стандарта и в реальности является легким способом для программиста чтобы отменить изменения частично в обратном порядке.

Выполнение команды COMMIT это тот момент когда многие люди (и даже некоторые администраторы БД) показывают непонимание архитектуры Oracle. Когда вы выполняете COMMIT всё что происходит физически это LGWR записывает буфер логов на диск. DBWn не делает абсолютно ничего. Это одно из самых важных свойств Oracle для достижения высокой производительность БД.

Exam tip

Что делает DBWn в момент выполнения команды COMMIT? Ответ: абсолютно ничего

Чтобы сделать транзакцию долговечной всё что нужно это записать изменения которые были сделаны в процессе транзакции на диск: нет необходимости в актуальных данных на диске. Если изменения записаны, в виде многих копий логов изменений на диске, то даже в случае повреждения базы все транзакции могут быт повторены восстановив резеврную копию данных до ошибки и применив изменения из логов. На данный момент надо понимать тот факт что COMMIT всего лишь очищает буфер лога на диск и помечает транзакцию как выполненную. Вот почему транзакции в которой были задействованы миллионы обновлений в тысячах файлов в течение нескольких часов могут подветрждаться за долю секунды. Так как LGWR записывает логи практически в режиме реального времени, то виртуально все изменения транзакции уже записаны на диск. Когда вы выполняете COMMIT, LGWR тут же записывает лог на диск: ваша сессия будет ожидать пока запись не закончится. Время задержки будет равно времени которое занимает запись последних данных из буфера логов, что обычно занимает несколько миллисекунд. Потом ваша сессия может продолжать работу и все остальные сессии не будут перенаправлятьяс на данные в сегменте отката при обращении к обновлённым данным, если только принцип согласованности не требует этого. Вектора изменений, записываемыe в лог повтора изменений, это все изменения: применяемых и к блокам данных (таблиц и индексов) и к блокам отката.

EXAM TIP

Лог redo включает все изменения: применяемые к сегментам данным и к сегментам undo для потдвержденных и неподтвержденных транзакций

Самое непонятное это то что redo записывается LGWR в файлы будет содержать и подтвержденные и неподтвержденные транзакции. Даже больше, в любой момент DBWn может записать а может и не записать измененные блоки сегментов данных или сегментов отката в файлы данных для подтверждённых и неподтверждённых транзакций. То есть ваша БД на диске противоречива: файлы данных могут хранить данные неподтверждённых транзакций и в них могут отсутствовать подтверждённые изменения. Но в любой момент, в случае проблемы, в файле логов на диске достаточно информации чтобы повторить подтверждённые транзакции которые пропущены в файлах данных (используя изменения для блоков данных) и восстановить сегменты отката (используя изменения блоков отката) нужные для отмены всех неподтверждённых транзакций которые записаны в файлы данных.

Exam tip

Лбая DDL команда, а также GRANT или REVOKE подтвердят текущую транзакцию

Пока транзакция в процессе, Oracle хранит образ данных до начала транзакции. Этот образ используется другими сессиями которые обращаются к данным участвующим в транзакции. Также он используется для отменты транзакции автоматически если что-то пойдёт не так или сессия отменит транзакцию.

Синтаксис для отмены транзакции

ROLLBACK ;

Состояние данных перед отменой транзакции содержит изменения, но информация нужная для отмены этих изменений доступна. Эта информация используется другими сессиями для выполнения принципа изолированности. ROLLBACK транзакции отменит все изменения восстановив образ данных до начала транзакции: все добавленные строки будут удалены, все удалённые строки восстановлены, все строки в которых менялись значения вернутся к исходному состоянию. Другие сессии даже не будут знать что что-то происходило, они никогда не видели изменений. А сессия которая инициировала транзакцию после отмены будет видеть данные такими какими они были до начала транзакции.

Точка сохранения позволяет программистам устанавливать флаг в транзакции которые затем можно использовать для контроля эффекта отмены транзакции. Вместо отмены всей транзакции и её завершения, становится возможным отменить изменения сделанные после конкретного флага но оставить изменения сделанные до этого флага. Действие транзакции в этот момент продолжается: транзакция не подтверждена, всё ещё можно отменить транзакцию целиком и изменения не видны для других сессий.

Синтаксис команды

SAVEPOINT savepoint

Такая команда создаёт точку в транзакции которая может быть использована в дальнейшем в команде ROLLBACK. На следующей таблице видно количество строк в таблице видимое разным сессиям во время работы транзакции в разные моменты времени. Используемая таблица назвается TAB и у неё один столбец

В примере с выполнены две транзакции: первая завершена командой COMMIT а вторая ROLLBACK. Видно что использование точек сохранения влияет только внутри транзакции для той сессии которая инициировала транзакцию: вторая сессия не видит ничего что не подтверждено.

SELECT FOR UPDATE

Последняя команда для управления транзакциями это SELECT FOR UPDATE. Oracle, по умолчанию, предоставляет наивысший уровень параллелизма: чтение данных не блокирует запись, запись не блокирует изменение. Другими словами нет проблемы если одна сессия пытается считать данные которые другая сессия изменяет и наоборот. Но иногда вам может понадобиться изменить такое поведение и предотвратить возможность изменения данных которые считаны сессией.

Типичное поведение приложений это выборка данных с помощью команды SELECT, отображение данных пользователю для просмотра и возможность изменения этих данных. Так как Oracle поддерживает параллельную работу пользователей то ничто не мешает другому пользователю получить те же данные. Если обе сессии попробует сделать какие-либо изменения, то могут возникнуть странные ситуации. Следующий пример показывает такую ситуацию

Вот что увидит первый пользователь (прелположим что используется SQL *Plus)

Такой результат немного смущает пользователя. Чтобы решить эту проблему можно заблокировать строки которые вернул запрос

select * from regions for update;

Директива FOR UPDATE приведёт к блокировке таблиц которые возвращает запрос. Другие сессии не смогут изменить данные и таким образом последующие изменения будут успешны: другие сессии не смогут изменить данные. То есть у одной сессии будет согласованное чтение данных, но ценой за это будет то, что другие сессии «зависнут» если они попытаются изменить данные которые заблокированы (другие сессии могут читать эти данные).

Блокировка строк вызванная командой FOR UPDATE будет длиться пока сессия не выполнит команду COMMIT или ROLLBACK. Команду завершения транзакции необходимо выполнить даже если вы не запускали каких-либо DML команд.

Так называемый «авто-коммит»

Чтоб завершить обзор как обрабатывается управление транзакциями надо рассеять все сомнения о так называемом “auto-commit” или неявном подтверждении (implicit commit). Вы будете часто слышать что Oracle автоматически подтвердит. Первый случай это предыдущий случай когда вы выполнили команду DDL, другая ситуация когда пользователь вышел из программы такой как SQL *Plus.

На самом деле всё очень просто. Не существует такого понятия как авто-коммит. Когда вы выполняете DDL команду, то работает обычный COMMIT которые встроен в команду DDL. Но что проиходит когда вы выходите из программы? Если вы используете SQL Plus в Windows и выполняете команду DML а затем команду EXIT (EXIT это команду SQL *Plus а не SQL), ваша транзакция будет подтверждена. Это потому что разработчики SQL *Plus встроили вызов команды COMMIT в команду EXIT. Если же вы нажмёте на красный крест в правом верхнем углу – то произойдёт вызов команды ROLLBACK. Так происходит потому что опять же разработчики SQL *Plus запрограммировали такое поведение программы. В другой операционной системе поведение программы SQL Plus может быть другим, единственный способ узнать это – это протестировать программу (или прочитать исходный код что в случае программы SQL Plus невозможно если вы не работаете в Oracle надо этой программой).

В SQL *Plus есть команда SET AUTOCOMMIT ON. Вызов этой команды указывает SQL *Plus на то как обрабатывать пользовательские запросы: SQL *Plus добавит вызов команды COMMIT после любой DML команды. Таким образом все запросы будут подтверждаться как только они выполнены. Но опять же всё это происходит полностью на стороне пользовательского процесса; у базы данных нет никакого авто-коммита, и все долго-работающие изменения будут изолированы от других сессий пока запрос не выполнится успешно. Даже в таком случае если вы запустите долгий запрос на выполнение, потом к примеру завершите пользовательский процесс через диспетчер задач то PMON обнаружит сессию «призрак» и отменит транзакцию.

Управление транзакциями

Транзакция — это последовательность операций над БД, рассматриваемых СУБД как единое целое. Либо транзакция успешно выполняется, и СУБД фиксирует (COMMIT) изменения БД, произведенные этой транзакцией, во внешней памяти, либо ни одно из этих изменений никак не отражается на состоянии БД. Понятие транзакции необходимо для поддержания логической целостности БД. Если вспомнить наш пример информационной системы с файлами СОТРУДНИКИ и ОТДЕЛЫ, то единственным способом не нарушить целостность БД при выполнении операции приема на работу нового сотрудника является объединение элементарных операций над файлами СОТРУДНИКИ и ОТДЕЛЫ в одну транзакцию. Таким образом, поддержание механизма транзакций является обязательным условием даже однопользовательских СУБД (если, конечно, такая система заслуживает названия СУБД). Но понятие транзакции гораздо более важно в многопользовательских СУБД.

То свойство, что каждая транзакция начинается при целостном состоянии БД и оставляет это состояние целостным после своего завершения, делает очень удобным использование понятия транзакции как единицы активности пользователя по отношению к БД. При соответствующем управлении параллельно выполняющимися транзакциями со стороны СУБД каждый из пользователей может в принципе ощущать себя единственным пользователем СУБД (на самом деле, это несколько идеализированное представление, поскольку в некоторых случаях пользователи многопользовательских СУБД могут ощутить присутствие своих коллег).

С управлением транзакциями в многопользовательской СУБД связаны важные понятия сериализации транзакций и сериального плана выполнения смеси транзакций. Под сериализаций параллельно выполняющихся транзакций понимается такой порядок планирования их работы, при котором суммарный эффект смеси транзакций эквивалентен эффекту их некоторого последовательного выполнения. Сериальный план выполнения смеси транзакций — это такой план, который приводит к сериализации транзакций. Понятно, что если удается добиться действительно сериального выполнения смеси транзакций, то для каждого пользователя, по инициативе которого образована транзакция, присутствие других транзакций будет незаметно (если не считать некоторого замедления работы по сравнению с однопользовательским режимом).


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

Журнализация

Одним из основных требований к СУБД является надежность хранения данных во внешней памяти. Под надежностью хранения понимается то, что СУБД должна быть в состоянии восстановить последнее согласованное состояние БД после любого аппаратного или программного сбоя. Обычно рассматриваются два возможных вида аппаратных сбоев: так называемые мягкие сбои, которые можно трактовать как внезапную остановку работы компьютера (например, аварийное выключение питания), и жесткие сбои, характеризуемые потерей информации на носителях внешней памяти. Примерами программных сбоев могут быть: аварийное завершение работы СУБД (по причине ошибки в программе или в результате некоторого аппаратного сбоя) или аварийное завершение пользовательской программы, в результате чего некоторая транзакция остается незавершенной. Первую ситуацию можно рассматривать как особый вид мягкого аппаратного сбоя; при возникновении последней требуется ликвидировать последствия только одной транзакции.

Понятно, что в любом случае для восстановления БД нужно располагать некоторой дополнительной информацией. Другими словами, поддержание надежности хранения данных в БД требует избыточности хранения данных, причем та часть данных, которая используется для восстановления, должна храниться особо надежно. Наиболее распространенным методом поддержания такой избыточной информации является ведение журнала изменений БД.

Журнал — это особая часть БД, недоступная пользователям СУБД и поддерживаемая с особой тщательностью (иногда поддерживаются две копии журнала, располагаемые на разных физических дисках), в которую поступают записи обо всех изменениях основной части БД. В разных СУБД изменения БД журнализуются на разных уровнях: иногда запись в журнале соответствует некоторой логической операции изменения БД (например, операции удаления строки из таблицы реляционной БД), иногда — минимальной внутренней операции модификации страницы внешней памяти; в некоторых системах одновременно используются оба подхода.

Во всех случаях придерживаются стратегии «упреждающей» записи в журнал (так называемого протокола Write Ahead Log — WAL). Грубо говоря, эта стратегия заключается в том, что запись об изменении любого объекта БД должна попасть во внешнюю память журнала раньше, чем измененный объект попадет во внешнюю память основной части БД. Известно, что если в СУБД корректно соблюдается протокол WAL, то с помощью журнала можно решить все проблемы восстановления БД после любого сбоя.

Самая простая ситуация восстановления — индивидуальный откат транзакции. Строго говоря, для этого не требуется общесистемный журнал изменений БД. Достаточно для каждой транзакции поддерживать локальный журнал операций модификации БД, выполненных в этой транзакции, и производить откат транзакции путем выполнения обратных операций, следуя от конца локального журнала. В некоторых СУБД так и делают, но в большинстве систем локальные журналы не поддерживают, а индивидуальный откат транзакции выполняют по общесистемному журналу, для чего все записи от одной транзакции связывают обратным списком (от конца к началу).

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

Для восстановления БД после жесткого сбоя используют журнал и архивную копию БД. Грубо говоря, архивная копия — это полная копия БД к моменту начала заполнения журнала (имеется много вариантов более гибкой трактовки смысла архивной копии). Конечно, для нормального восстановления БД после жесткого сбоя необходимо, чтобы журнал не пропал. Как уже отмечалось, к сохранности журнала во внешней памяти в СУБД предъявляются особо повышенные требования. Тогда восстановление БД состоит в том, что исходя из архивной копии по журналу воспроизводится работа всех транзакций, которые закончились к моменту сбоя. В принципе, можно даже воспроизвести работу незавершенных транзакций и продолжить их работу после завершения восстановления. Однако в реальных системах это обычно не делается, поскольку процесс восстановления после жесткого сбоя является достаточно длительным.

Поддержка языков БД

Для работы с базами данных используются специальные языки, в целом называемые языками баз данных. В ранних СУБД поддерживалось несколько специализированных по своим функциям языков. Чаще всего выделялись два языка — язык определения схемы БД (SDL — Schema Definition Language) и язык манипулирования данными (DML — Data Manipulation Language). SDL служил главным образом для определения логической структуры БД, т.е. той структуры БД, какой она представляется пользователям. DML содержал набор операторов манипулирования данными, т.е. операторов, позволяющих заносить данные в БД, удалять, модифицировать или выбирать существующие данные. Мы рассмотрим более подробно языки ранних СУБД в следующей лекции.

В современных СУБД обычно поддерживается единый интегрированный язык, содержащий все необходимые средства для работы с БД, начиная от ее создания, и обеспечивающий базовый пользовательский интерфейс с базами данных. Стандартным языком наиболее распространенных в настоящее время реляционных СУБД является язык SQL (Structured Query Language). В нескольких лекциях этого курса язык SQL будет рассматриваться достаточно подробно, а пока мы перечислим основные функции реляционной СУБД, поддерживаемые на «языковом» уровне (т.е. функции, поддерживаемые при реализации интерфейса SQL).

Прежде всего, язык SQL сочетает средства SDL и DML, т.е. позволяет определять схему реляционной БД и манипулировать данными. При этом именование объектов БД (для реляционной БД — именование таблиц и их столбцов) поддерживается на языковом уровне в том смысле, что компилятор языка SQL производит преобразование имен объектов в их внутренние идентификаторы на основании специально поддерживаемых служебных таблиц-каталогов. Внутренняя часть СУБД (ядро) вообще не работает с именами таблиц и их столбцов.

Язык SQL содержит специальные средства определения ограничений целостности БД. Опять же, ограничения целостности хранятся в специальных таблицах-каталогах, и обеспечение контроля целостности БД производится на языковом уровне, т.е. при компиляции операторов модификации БД компилятор SQL на основании имеющихся в БД ограничений целостности генерирует соответствующий программный код.

Специальные операторы языка SQL позволяют определять так называемые представления БД, фактически являющиеся хранимыми в БД запросами (результатом любого запроса к реляционной БД является таблица) с именованными столбцами. Для пользователя представление является такой же таблицей, как любая базовая таблица, хранимая в БД, но с помощью представлений можно ограничить или наоборот расширить видимость БД для конкретного пользователя. Поддержание представлений производится также на языковом уровне.

Наконец, авторизация доступа к объектам БД производится также на основе специального набора операторов SQL. Идея состоит в том, что для выполнения операторов SQL разного вида пользователь должен обладать различными полномочиями. Пользователь, создавший таблицу БД, обладает полным набором полномочий для работы с этой таблицей. В число этих полномочий входит полномочие на передачу всех или части полномочий другим пользователям, включая полномочие на передачу полномочий. Полномочия пользователей описываются в специальных таблицах-каталогах, контроль полномочий поддерживается на языковом уровне.

Более точное описание возможных реализаций этих функций на основе языка SQL будет приведено в лекциях, посвященных языку SQL и его реализации.

  1. Запуск транзакции
  2. Завершение транзакции

Управление транзакциями в Delphi

Обзор

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

SQL-выражения для управления транзакциями

Для управления транзакциями имеется три выражения:

SET TRANSACTION — Начинает транзакцию и определяет ее поведение.

COMMIT — Сохраняет изменения, внесенные транзакцией, в базе данных и завершает транзакцию.

ROLLBACK — Отменяет изменения, внесенные транзакцией, и завершает транзакцию.

1. Запуск транзакции

Выполнять транзакции можно, например, из Windows Interactive SQL, из программы, из сохраненной процедуры или триггера. В общем виде, синтаксис команды SQL для запуска транзакции:

SET TRANSACTION Значения, принимаемые по-умолчанию:
выражение
SET TRANSACTION равносильно выражению
SET TRANSACTION READ WRITE WAIT ISOLATION LEVEL SNAPSHOT

Access Mode — определяет тип доступа к данным. Может принимать два значения:

  • READ ONLY — указывает, что транзакция может только читать данные и не может модифицировать их.
  • READ WRITE — указывает, что транзакция может читать и модифицировать данные. Это значение принимается по умолчанию.

Пример:

SET TRANSACTION READ WRITE

Isolation Level — определяет порядок взаимодействия данной транзакции с другими в данной базе. Может принимать значения:

  • SNAPSHOT — значение по умолчанию. Внутри транзакции будут доступны данные в том состоянии, в котором они находились на момент начала транзакции. Если по ходу дела в базе данных появились изменения, внесенные другими завершенными транзакциями, то данная транзакция их не увидит. При попытке модифицировать такие записи возникнет сообщение о конфликте.
  • SNAPSHOT TABLE STABILITY — предоставляет транзакции исключительный доступ к таблицам, которые она использует. Другие транзакции смогут только читать данные из них.
  • READ COMMITTED — позволяет транзакции видеть текущее состояние базы.

Конфликты, связанные с блокировкой записей происходят в двух случаях:

  • Транзакция пытается модифицировать запись, которая была изменена или удалена уже после ее старта. Транзакция типа READ COMMITTED может вносить изменения в записи, модифицированные другими транзакциями после их завершения.
  • Транзакция пытается модифицировать таблицу, которая заблокирована другой транзакцией типа SNAPSHOT TABLE STABILITY.

Lock Resolution — определяет ход событий при обнаружении конфликта блокировки. Может принимать два значения:

  • WAIT — значение по умолчанию. Ожидает разблокировки требуемой записи. После этого пытается продолжить работу.
  • NO WAIT — немедленно возвращает ошибку блокировки записи.

Table Reservation — позволяет транзакции получить гарантированный доступ необходимого уровня к указанным таблицам. Существует четыре уровня доступа:

  • PROTECTED READ — запрещает обновление таблицы другими транзакциями, но позволяет им выбирать данные из таблицы.
  • PROTECTED WRITE — запрещает обновление таблицы другими транзакциями, читать данные из таблицы могут только транзакции типа SNAPSHOT или READ COMMITTED.
  • SHARED READ — самый либеральный уровень. Читать могут все, модифицировать — транзакции READ WRITE.
  • SHARED WRITE — транзакции SNAPSHOT или READ COMMITTED READ WRITE могут модифицировать таблицу, остальные — только выбирать данные.

2. Завершение транзакции

Когда все действия, составляющие транзакцию успешно выполнены или возникла ошибка, транзакция должна быть завершена, для того, чтобы база данных находилась в непротиворечивом состоянии. Для этого есть два SQL-выражения:

  • COMMIT — сохраняет внесенные транзакцией изменения в базу данных. Это означает, что транзакция завершена успешно.
  • ROLLBACK — откат транзакции. Транзакция завершается и никаких изменений в базу данных не вносится. Данная операция выполняется при возникновении ошибки при выполнении операции (например, при невозможности обновить запись).

Управление транзакциями в Delphi

Прежде всего, транзакции в Delphi бывают явные и неявные.

Явная транзакция — это транзакция, начатая и завершенная с помощью методов объекта DataBase:StartTransaction, Commit, RollBack. После начала явной транзакции, все изменения, вносимые в данные относятся к этой транзакции.

Другого способа начать явную транзакцию, нежели с использованием DataBase, нет. (Точнее говоря, такая возможность есть, но это потребует обращения к функциям API InterBase. Однако, это уже достаточно низкоуровневое программирование.) Следовательно, в рамках одного соединения нельзя начать две транзакции.

Неявная транзакция стартует при модификации данных, если в данный момент нет явной транзакции. Неявная транзакция возникает, например, при выполнении метода Post для объектов Table и Query. То есть, если Вы отредактировали запись, в DBGrid и переходите на другую запись, то это влечет за собой выполнение Post, что, в свою очередь, приводит к началу неявной транзакции, обновлению данных внутри транзакции и ее завершению. Важно отметить, что неявная транзакция, начатая с помощью методов Post, Delete, Insert, Append и т.д. заканчивается автоматически.

Для модификации данных может использоваться и PassThrough SQL — SQL-выражение, выполняемое с помощью метода ExecSQL класса TQuery. Выполнение модификации через PassThrough SQL также приводит к старту неявной транзакции. Дальнейшее поведение транзакции, начатой таким путем, определяется значением параметра SQLPASSTHRU MODE для псевдонима базы данных (или тот-же параметр в св-ве Params объекта DataBase). Этот параметр может принимать три значения:

  • SHARED AUTOCOMMIT — слово SHARED указывает на то, что оба вида транзакций(через Passthrough SQL и через методы TTable и TQuery) разделяют одно и то же соединение к базе данных. Слово AUTOCOMMIT указывает на то, что неявная транзакция, начатая через Passthrough SQL, завершается после выполнения действия по модификации данных (автоматически выполняется COMMIT).
  • SHARED NOAUTOCOMMIT — отличается от предыдущего тем, что неявная транзакция, начатая через Passthrough SQL, не завершается после выполнения, ее нужно явно завершить, выполнив SQL-выражение «COMMIT».
  • NOT SHARED — транзакции разных типов работают через разные соединения с базой. Данное значение параметра подразумевает также NOAUTOCOMMIT. То есть все неявные PassthroughSQL-транзакции нужно завершать явно — выполняя SQL-выражение «COMMIT» для Passtrough SQL.

Рассмотрим возможные сценарии поведения транзакций при разных значениях параметра.

В первом случае, если нет в данный момент начатой транзакции, то попытка модификация данных методами TTable или TQuery, как и выполнение через Passtrough SQL какой-либо операции приведет к старту неявной транзакции. После выполнения, такая транзакция будет автоматически завершена (если не возникло ошибки по ходу транзакции). Если уже имеется начатая явно (метод StartTransaction объекта DataBase) транзакция, то изменения будут проходить в ее контексте. Все транзакции используют одно и то-же соединение.

Во втором случае все происходит, как в первом. Отличие в том, что неявная PassthroughSQL-транзакция не завершается, пока не будет выполнена команда «COMMIT».

В третьем случае, при выполнении команды Passthrough SQL, будет установлено еще одно соединение, начата неявная транзакция и выполнены действия по модификации данных. Транзакция не будет завершена, пока не будет выполнена команда «COMMIT». Наличие транзакции, начатой явно с помощью DataBase никак не отразится на ходе выполнения PassthroughSQL-транзакции. Пока PassthroughSQL-транзакция не завершится, изменения, внесенные ей, не будут видны в объектах Table и Query, работающих через другое соединение. PassthroughSQL-транзакции можно рассматривать в некотором смысле, как транзакции из другого приложения.

Взаимодействие транзакций данной программы с транзакциями из других приложений определяется свойством TransIsolation объекта DataBase. Для InterBase имеет смысл два значения: tiReadCommitted и tiRepeatableRead. Выполнение метода StartTransaction в этих двух случаях равносильно выполнению SQL-выражений, соответственно:

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *

Наверх