Объектные блокировки. Блокирование и разблокирование

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

Процессор Баз Данных обеспечивает три уровня блокировок:

* Блокировка Базы Данных. На этом уровне блокировки к Базе Данных может обращаться только один пользователь. Такой уровень блокировки применяется для глобального изменения или обновления данных или при техническом обслуживании Базы Данных- сжатии;
* Блокировка Таблицы. На этом уровне блокировки к таблице может обращаться только один пользователь. Такой уровень блокировки применяется в тех случаях, когда необходимо обработать сразу несколько записей таблицы.
* Блокировка страницы. На этом уровне к заблокированной странице может обращаться только один пользователь. Это самый нижний уровень блокировки.

Блокировка Базы Данных

Блокиривка на уровне Базы Данных осуществляется присвоением свойству exclusive, при открытии БД, значения true. При использовании вами элемента управления data, в его свойствах установите exclusive = true . Если же вы используете объект dao, то при присвоении значения объекту db установите в true значение второго параметра метода opendatabase:

set db = dbengine.opendatabase(“c:biblio.mdb”, true)

Когда База Данных заблокирована таким образом, тодругие пользователи не смогут ее открыть. При попытке обращения к заблокированной Базе Данных вы получите сообщение:

“couldn’t use ‘c:biblio.mdb’; file already in use.” “Невозможно использовать ‘c:biblio.mdb’; файл уже используется”

Одновременно с этим генерируется перехватываемая ошибка – 3045, используя которую вы можете завершить программу, которая обращается к заблокированной Базе Данных, т.к. после возникновения ошибки программа продолжает выполняться, хотя База Данных так и не была открыта.
При использовании элемента управления data в обработчик события error вставляется следующий код:

private sub data1_error(dataerr as integer, response as integer) if err = 3045 then msgbox "Доступ к Базе Данных закрыт. Повторите запрос через несколько минут." & ,vbcritical, "data_error" end end if end sub

При использовании объекта dao в той процедуре, где будет стоять код открытия Базы Данных, вставляется обработчик ошибок:

on error goto errhandler "Здесь вставляется код открытия БД и если возникает ошибка – 3045, то она "перехватывается и обрабатывается errhandler: if err = 3045 then msgbox "Доступ к Базе Данных закрыт. Повторите запрос черезнесколько минут." & _ ,vbcritical, "data_error" end end if

Блокировка Таблицы

Блокировка на уровне таблицы применяется при глобальных изменениях в отдельно взятой таблице. После того как вы проведете ваши изменения и закроете эту таблицу, толкко тогда к ней получат доступ другие пользователи. . При использовании вами элемента управления data, в его свойствах установите exclusive = false, для того, чтобы пользователи имели доступ к Базе Данных, а свойствu option присвойте значение 3. Это приведет к томы, что выбранная вами таблица (к примеру authors) будет открыта с параметрами denywrite(1) и denyread(2), что запрещает другим пользователям открывать эту таблицу во время действия вашей программы. При попытке обращения к заблокированной таблице вы получите сообщение:
“couldn’t lock table ‘authors’;currently in use by user ‘admin’ on machine ‘user-0000011660’ “
“Невозможно зблокировать таблицу ‘authors’ , т.к. она используется администратором машины ‘user-0000011660’ “

Одновременно с этим генерируется перехватываемая ошибка – 3265, используя которую вы можете завершить программу, которая обращается к заблокированной таблице, т.к. после возникновения ошибки программа продолжает выполняться, хотя таблица так и не была открыта. При использовании элемента управления data в обработчик события error вставляется следующий код, но предварительно дополняя предыдущий:

private sub data1_error(dataerr as integer, response as integer) select case err case 3045 msgbox "Доступ к Базе Данных закрыт. Повторите запрос черезнесколько минут." & _ ,vbcritical, "data_error" end case 3265 msgbox "Доступ к таблице закрыт. Повторите запрос через несколько минут." & ,vbcritical, "data_error" end end select end sub

Если же вы используете объект dao, то при присвоении значения объекту db установите в false значение второго параметра метода opendatabase:
set db = dbengine.opendatabase(“c:biblio.mdb”, false)
а, при присвоении значении объекту recordset:
set rs = db.openrecordset(“authors”, dbopentable, dbdenyread + dbdenywrite)

Для перехвата возникающей ошибки опять ставте код:

on error goto errhandler "Здесь вставляется код открытия таблицы и если возникает ошибка – 3265, то она "перехватывается и обрабатывается errhandler: if err = 3265 then msgbox "Доступ к таблице закрыт. Повторите запрос черезнесколько минут." & _ ,vbcritical, "data_error" end end if

Здесь указан только обработчик ошибки открытия блокированной таблицы, т.к. Базу Данных вы можете открыть в другой процедуре, в отличае от элемента data.
Внимание! Если вы откроете приложении access в то время, когда у вас стоит блокировка таблицы (во время работы вашей программы), то данная таблица открывается без извещения вас диалоговым окном о том, что таблица заблокирована. Но, при всем желании вы не сможете сделать запись или произвести редактирование какой либо записи.

Блокировка страницы

Самым нижнем уровнем блокировки является уровень таблицы. Процессор microsoft jet автоматически устанавливает блокировку страницы и не может контролироваться вашей программой. Страница данных может содержатьнесколько записей, размер его равен 26 кб. Блокировка страницы означает блокировкувсех записей, находящейся на этой странице. Если длина записи – 512 байтов, то будет заблокированно 4 записи, а если 50 байтов то 40 записей. Точное число записей нельзя заранее ни определить ни задать, т.к. таблица может содержать удаленные записи (которые удаляются только во время уплотнения). Но, не смотря на это объект recordset имеет свойство lockedits, которое позволяетуправлять страничной блокировкой из программы.
Блокировка на уровне таблицы имеетдва режима – пессимистический (lockedits ю true) и оптимистический (lockedits = false). По умолчанию устанавливается пессимистическая блокировка.
Пессимистическая блокировка блокирует страницу при вызове методов edit и addnew, и остается заблокированной до тех пор пока не будетвыполнен метод update или cancelupdate. В течении всего времени ни одна программа не имеет доступа к забликированной странице.
Преимущества. Обеспечивается максимально возможныйуровень целостности данных.
Недостатки. Страница может быть заблокирована в течении продолжительного времени.
Оптимистическая блокировка блокирует страницу только при вызове метода update. Это означает, что пользователь вызывает методы edit и addnew, производит действия с дсанными, и только в момент сохранения обновления процессор microsoft jet пытается заблокировать страницу. Если все проходит успешно, то запись попадает в таблицу, но если обнаружится, что эта запись уже была отредактированна, то обновление отменяется и пользователь получаетсообщение о том, что данные были уже кем-то изменены.
Преимущества. Страница блокируется на минимально возвожное время, тен самым уменьшаетсячисло сообщений о блокировках.
Недостатки. Может привести к ошибкам блокировки при одновременном редактировании записи двумя пользователями, когда они будут проводить обновление.
Програмно это осуществляется следующим образом:

* для элемента data — data1.recordset.lockedits = true (или false);
* для объекта dao – rs.lockedits = true (или false);

При работе с пессиместической и оптимистической блокировкой используется вызов idle. Этот метод приостанавливает выполнение программы на visual basic на время обнавления динамических и статических наборов, которые были открыты этой программой. Вызов этого метода гарантирует, что в вашу программу попадут самые последние изменения в наборе данных.
Програмно это осуществляется следующим образом.

Типы управления одновременным доступом нескольких пользователей к данным:

  • пессимистическое - в одно и тоже время просматривать и изменять данные может только один пользователь.
  • оптимистическое - в одно и тоже время просматривать данные могут несколько пользователей, но изменять данные может только один пользователь.

Оба типа управления одновременным доступом к данным используют в своей работе блокировки данных. Блокировка - это объект, с помощью которого показывается зависимость пользователя от какого-либо ресурса. Система управления блокировками запрещает другим пользователям выполнять над ресурсами операции, негативно влияющие на зависимость пользователя, владеющего блокировкой, от этого ресурса. Блокировка создает временное ограничение на выполнение некоторых операций обработки тех данных, от которых зависит пользователь. Основные типы блокировок:

  • разделяемая (shared, S) - накладывается при выполнении операций чтения данных (например, SELECT). Никакая другая транзакция не сможет изменить или удалить данные, если на них установлена разделяемая блокировка. Разделяемая блокировка обычно освобождается после завершения чтения данных, но если только уровень изоляции транзакции установлен в REPEATABLE READ или выше, то разделяемая блокировка сохраняется до завершения транзакции.
  • монопольная (exclusive, X) - накладывается при выполнении операций изменения данных (например, UPDATE). Никакая другая транзакция не сможет ни изменить, ни даже прочитать данные, если на них установления монопольная блокировка. Исключение: прочитать данные с установленной монопольной блокировкой возможно, если только уровень изоляции транзакции установлен в READ UNCOMMITTED. Монопольная блокировка освобождается после завершения транзакции.

Для просмотра установленных блокировок в Microsoft SQL Server используется системная хранимая процедура sp_lock.
Транзакция - последовательность операций, выполняемая как целостная логическая единица работы. Свойства транзакции:

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

Оператор BEGIN TRAN используется для начала транзакции. Для завершения транзакции используется либо оператор COMMIT TRAN (используется в том случае, если транзакция завершается успешно и все действия, выполнении в рамках транзакции должны быть сохранены в базе данных), либо оператор ROLLBACK TRAN (используется в том случае, если транзакция завершается с ошибками и все действия, выполнении в рамках транзакции должны быть отменены). Синтаксис транзакции выглядит так:

BEGIN TRAN
{операторы SQL}

{если ошибок не было}
COMMIT TRAN
{иначе, если возникли ошибки}
ROLLBACK TRAN

Управление транзакциями осуществляется на уровне соединения, а не пользователя. После начала транзакции в соединении и до ее успешного или неуспешного завершения все выполненные в этом соединении операторы SQL становятся частью транзакции.

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

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

Для управления взаимодействия транзакций между собой и, соответственно, управлением блокировками данных, возникающими при выполнении транзакций, используется установка уровня изоляции транзакции. Уровень изоляции транзакции определяет, какие блокировки накладываются на данные, обрабатываемые в рамках транзакций. Оператор SET TRANSACTION ISOLATION LEVEL используется для изменения уровня изоляции транзакции.

Синтаксис оператора SET TRANSACTION ISOLATION LEVEL выглядит так:

SET TRANSACTION ISOLATION LEVEL {уровень изоляции}

В языке SQL допустимы следующие уровни изоляции транзакции:

  • READ UNCOMMITTED (неподтвержденное чтение) - транзакция с этим уровнем изоляции может читать записи, которые были изменены, но еще не зафиксированы другой транзакцией.
  • READ COMMITTED (подтвержденное чтение) - транзакция с этим уровнем изоляции может читать только те записи, которые были изменены и уже зафиксированы другой транзакцией.
  • REPEATABLE READ (повторяемое чтение) - транзакция с этим уровнем изоляции может читать только те записи, которые были изменены и уже зафиксированы другой транзакцией, и никакая другая транзакция не может изменить записи, которые были прочитаны в рамках этой транзакции.
  • SERIALIZABLE (упорядочение) - транзакция с этим уровнем изоляции может читать только те записи, которые были изменены и уже зафиксированы другой транзакцией; никакая другая транзакция не может изменить записи, которые были прочитаны в рамках этой транзакции и никакая другая транзакция не может добавить или удалить записи из диапазона записей, прочитанного в рамках этой транзакции.

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

Одновременный конкурентный доступ может вызывать разные отрицательные эффекты, например чтение несуществующих данных или потерю модифицированных данных. Рассмотрим следующий практический пример, иллюстрирующий один из этих отрицательных эффектов, называемый грязным чтением. Пользователь U1 из отдела кадров получает извещение, что сотрудник "Василий Фролов" поменял место жительства. Он вносит соответствующее изменение в базу данных для данного сотрудника, но при просмотре другой информации об этом сотруднике он понимает, что изменил адрес не того человека. (В компании работают два сотрудника по имени Василий Фролов.) К счастью, приложение позволяет отменить это изменение одним нажатием кнопки. Он нажимает эту кнопку, уверенный в том, что данные после отмены операции изменения адреса уже не содержат никакой ошибки.

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

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

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

Режимы блокировки и уровень гранулярности блокировки рассматриваются в следующих двух разделах. Последующее обсуждение относится к модели пессимистического одновременного конкурентного доступа. Модель оптимистического одновременного конкурентного доступа основана на управлении версиями строк и рассматривается в последующих статьях.

Режимы блокировки

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

Разделяемая блокировка (shared lock)

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

Монопольная блокировка (exclusive lock)

Резервирует страницу или строку для монопольного использования одной транзакции. Блокировка этого типа применяется инструкциями DML (INSERT, UPDATE и DELETE), которые модифицируют ресурс. Монопольную блокировку нельзя установить, если на ресурс уже установлена разделяемая или монопольная блокировка другим процессом, т.е. на ресурс может быть установлена только одна монопольная блокировка. На ресурс (страницу или строку) с установленной монопольной блокировкой нельзя установить никакую другую блокировку.

Блокировка обновления (update lock)

Может быть установлена на ресурс только при отсутствии на нем другой блокировки обновления или монопольной блокировки. С другой стороны, этот тип блокировки можно устанавливать на объекты с установленной разделяемой блокировкой. В таком случае блокировка обновления накладывает на объект другую разделяемую блокировку. Если транзакция, которая модифицирует объект, подтверждается, и у объекта нет никаких других блокировок, блокировка обновления преобразовывается в монопольную блокировку. У объекта может быть только одна блокировка обновления.

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

Возможность совмещения разных типов блокировок приводится в таблице ниже:

Эта таблица интерпретируется следующим образом: предположим транзакция T1 имеет блокировку, указанную в заголовке соответствующей строки таблицы, а транзакция T2 запрашивает блокировку, указанную в соответствующем заголовке столбца таблицы. Значение "Да" в ячейке на пресечении строки и столбца означает, что транзакция T2 может иметь запрашиваемый тип блокировки, а значение "Нет", что не может.

Компонент Database Engine также поддерживает и другие типы блокировок, такие как кратковременные блокировки (latch lock) и взаимоблокировки (spin lock).

На уровне таблицы существует пять разных типов блокировок:

    разделяемая (shared, S);

    монопольная (exclusive, X);

    разделяемая с намерением (intent shared, IS);

    монопольная с намерением (intent exclusive, IX);

    разделяемая с монопольным намерением (shared with intent exclusive, SIX).

Разделяемые и монопольные типы блокировок для таблицы соответствуют одноименным блокировкам для строк и страниц. Обычно блокировка с намерением (intent lock) означает, что транзакция намеревается блокировать следующий нижележащий в иерархии объектов базы данных ресурс. Таким образом, блокировка с намерением помещается на уровне иерархии объектов, который выше того объекта, который этот процесс намеревается заблокировать. Это является действенным способом узнать, возможна ли подобная блокировка, а также устанавливается запрет другим процессам блокировать более высокий уровень, прежде чем процесс может установить требуемую ему блокировку.

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

Возможность совмещения разных типов блокировок
S X IS SIX IX
S Да Нет Да Нет Нет
X Нет Нет Нет Нет Нет
IS Да Нет Да Да Да
SIX Нет Нет Да Нет Нет
IX Нет Нет Да Нет Да

Гранулярность блокировки

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

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

В кластеризованных таблицах страницы данных хранятся на уровне узлов (кластеризованной) индексной структуры, и поэтому для них вместо блокировки строк применяется блокировка с индексными ключами.

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

Гранулярность блокировки оказывает влияние на одновременный конкурентный доступ. В общем, чем выше уровень гранулярности, тем больше сокращается возможность совместного доступа к данным. Это означает, что блокировка уровня строк максимизирует одновременный конкурентный доступ, т.к. она блокирует всего лишь одну строку страницы, оставляя все другие строки доступными для других процессов. C другой стороны, низкий уровень блокировки увеличивает системные накладные расходы, поскольку для каждой отдельной строки требуется отдельная блокировка. Блокировка на уровне страниц и таблиц ограничивает уровень доступности данных, но также уменьшает системные накладные расходы.

Укрупнение блокировок

Если в процессе транзакции имеется большое количество блокировок одного уровня, то компонент Database Engine автоматически объединяет эти блокировки в одну уровня таблицы. Этот процесс преобразования большого числа блокировок уровня строки, страницы или индекса в одну блокировку уровня таблицы называется укрупнением блокировок (lock escalation) . Порогом укрупнения называется граница, на которой система баз данных применяет укрупнение блокировок. Пороги укрупнения устанавливаются динамически системой и не требуют настройки. (В настоящее время пороговым значением укрупнения блокировок является 5000 блокировок.)

Основной проблемой, касающейся укрупнения блокировок, является то обстоятельство, что решение, когда осуществлять укрупнение, принимает сервер баз данных, и это решение может не быть оптимальным для приложений, имеющих различные требования. Механизм укрупнения блокировок можно модифицировать с помощью инструкции ALTER TABLE. Эта инструкция поддерживает параметр TABLE и имеет следующий синтаксис:

Параметр table является значением по умолчанию и задает укрупнение блокировок на уровне таблиц. Параметр auto позволяет компоненту Database Engine самому выбирать уровень гранулярности, который соответствует схеме таблицы. Наконец, параметр disable отключает укрупнение блокировок в большинстве случаев. (В некоторых случаях компоненту Database Engine требуется наложить блокировку на уровне таблиц, чтобы предохранить целостность данных.)

В примере ниже показана отмена укрупнения блокировок для таблицы Employee:

USE SampleDb; ALTER TABLE Employee SET (LOCK_ESCALATION = DISABLE);

Настройка блокировок

Настройку блокировок можно осуществлять, используя подсказки блокировок (locking hints) или параметр LOCK_TIMEOUT инструкции SET. Эти возможности описываются в следующих разделах.

Подсказки блокировок (locking hints)

Подсказки блокировок задают тип блокировки, используемой компонентом Database Engine для блокировки табличных данных. Подсказки блокировки уровня таблиц применяются, когда требуется более точное управление типами блокировок, накладываемых на ресурс. (Подсказки блокировок перекрывают текущий уровень изоляции для сеанса.)

Все подсказки блокировок указываются в предложении FROM инструкции SELECT. Далее приводится список и краткое описание доступных подсказок блокировок:

UPDLOCK

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

TABLOCK

Устанавливается разделяемая (или монопольная) блокировка для таблицы. Все блокировки удерживаются до окончания транзакции.

ROWLOCK

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

PAGLOCK

Разделяемая блокировка таблицы заменяется разделяемой блокировкой страницы для каждой страницы, содержащей указанные строки.

NOLOCK

Синоним для READUNCOMMITTED, который мы рассмотрим при обсуждении уровней изоляции.

HOLDLOCK

Синоним для REPEATABLEREAD.

XLOCK

Устанавливается монопольная блокировка, удерживаемая до завершения транзакции. Если подсказка xlock указывается с подсказкой rowlock, paglock или tablock, монопольные блокировки устанавливаются на соответствующем уровне гранулярности.

READPAST

Указывает, что компонент Database Engine не должен считывать строки, заблокированные другими транзакциями.

Все эти параметры можно объединять вместе в любом имеющем смысл порядке. Например, комбинация подсказок TABLOCK с PAGLOCK не имеет смысла, поскольку каждая из них применяется для разных ресурсов.

Параметр LOCK_TIMEOUT

Чтобы процесс не ожидал освобождения блокируемого объекта до бесконечности, можно в инструкции SET использовать параметр LOCK_TIMEOUT. Этот параметр задает период в миллисекундах, в течение которого транзакция будет ожидать снятия блокировки с объекта. Например, если вы хотите чтобы период ожидания был равен восемь секунд, то это следует указать следующим образом:

SET LOCK_TIMEOUT 8000

Если данный ресурс не может быть предоставлен процессу в течение этого периода времени, инструкция завершается аварийно и выдается соответствующее сообщение об ошибке. Значение LOCK_TIMEOUT равное -1 (значение по умолчанию) указывает отсутствие периода ожидания, т.е. транзакция не будет ожидать освобождения ресурса совсем. (Подсказка блокировки READPAST предоставляет альтернативу параметру LOCK_TIMEOUT.)

Отображение информации о блокировках

Наиболее важным средством для отображения информации о блокировках является динамическое административное представление sys.dm_tran_locks . Это представление возвращает информацию о текущих активных ресурсах диспетчера блокировок. Каждая строка представления отображает активный в настоящий момент запрос на блокировку, которая была предоставлена или предоставление которой ожидается. Столбцы представления соответствуют двум группам: ресурсам и запросам. Группа ресурсов описывает ресурсы, на блокировку которых делается запрос, а группа запросов описывает запрос блокировки. Наиболее важными столбцами этого представления являются следующие:

    resource_type - указывает тип ресурса;

    resource_database_id - задает идентификатор базы данных, к которой принадлежит данный ресурс;

    request_mode - задает режим запроса;

    request_status - задает текущее состояние запроса.

В примере ниже показан запрос, использующий представление sys.dm_tran_locks для отображения блокировок в состоянии ожидания:

Взаимоблокировки

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

USE SampleDb; BEGIN TRANSACTION BEGIN TRANSACTION UPDATE Works_on UPDATE Employee SET Job = "Менеджер" SET DepartamentNumber = "d2" WHERE EmpId = 25348 WHERE Id = 28559 AND ProjectNumber = "p2" WAITFOR DELAY "00:00:10" WAITFOR DELAY "00:00:10" UPDATE Employee DELETE FROM Works_on SET LastName = "Фролова" WHERE EmpId = 25348 WHERE LastName = "Вершинина" AND ProjectNumber = "p2" COMMIT COMMIT

Если обе транзакции в примере выше будут выполняться в одно и то же время, то возникнет взаимоблокировка и система возвратит следующее сообщение об ошибке:

Сообщение 1205, уровень 13, состояние 45 Транзакция (процесс с идентификатором 56) находится во взаимной блокировке с другим процессом и выбрана в качестве потерпевшей взаимоблокировки. Повторите выполнение команды.)

Как можно видеть по результатам выполнения примера, система баз данных обрабатывает взаимоблокировку, выбирая одну из транзакций (на самом деле, транзакцию, которая замыкает цикл в запросах блокировки) в качестве "жертвы" и выполняя ее откат. После этого выполняется другая транзакция. На уровне прикладной программы взаимоблокировку можно обрабатывать посредством реализации условной инструкции, которая выполняет проверку на возврат номера ошибки (1205), а затем снова выполняет инструкцию, для которой был выполнен откат.

Вы можете повлиять на то, какая транзакция будет выбрана системой в качестве "жертвы" взаимоблокировки, присвоив в инструкции SET параметру DEADLOCK_PRIORITY один из 21 (от -10 до 10) разных уровней приоритета взаимоблокировки. Константа LOW соответствует значению -5, NORMAL (значение по умолчанию) - значению 0, а константа HIGH - значению 5. Сеанс "жертва" выбирается в соответствии с приоритетом взаимоблокировки сеанса.

Сегодня речь пойдет о блокировках как на уровне 1С 8.3 и 8.2, так и на уровне СУБД. Блокировка данных — обязательный элемент любой системы, количество пользователей в которой больше одного.

Ниже я распишу, как работают блокировки, и каких типов они бывают.

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

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

Блокировки в 1С делятся условно на объектные и транзакционные.

Объектные бывают, в свою очередь, оптимистическими и пессимистическими. А транзакционные можно разделить на управляемые и автоматические.

Объектные блокировки 1С

Данный вид блокировок полностью реализован на уровне платформы 1С и никак не затрагивает СУБД.

Получите 267 видеоуроков по 1С бесплатно:

Пессимистические блокировки

Эта блокировка срабатывает, когда один пользователь что-то изменил в форме справочника, а второй пытается так же изменить объект в форме.

Оптимистические блокировки

Данная блокировка сравнивает версии объекта: если два пользователя открыли форму, и один из них изменил и записал объект, то второму при записи система выдаст ошибку, что версии объектов отличаются.

Транзакционные блокировки 1С

Механизм тразакционных блокировок 1С гораздо интереснее и более функционален, чем механизм объектных блокировок. В этом механизме активно участвуют блокировки на уровне СУБД.

Неверная работа транзакционных блокировок может привести с следующим проблемам:

  • проблема потерянного изменения;
  • проблема грязного чтения;
  • неповторяемость чтения;
  • чтение фантомов.

Подробно эти проблемы были рассмотрены в статье об .

Автоматические транзакционные блокировки 1С и СУБД

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

Для разных СУБД в автоматическом режиме используются разные степени изоляции:

  • SERIALIZABLE на всю таблицу – файловый режим 1С, Oracle;
  • SERIALIZABLE на записи – MS SQL, IBM DB2 при работе с не объектными сущностями;
  • REPEATABLE READ на записи – MS SQL, IBM DB2 при работе с объектными сущностями.

Управляемые режим транзакционных блокировок 1С и СУБД

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

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

Две блокировки НЕ совместимы, если: установлены разными пользователями, имеют несовместимые виды (исключительная/разделяемая) и установлены на один и тот же ресурс.

Физическая реализация блокировок в СУБД

Физически блокировки представляют собой таблицу, которая находится в БД под названием master. Сама таблица блокировок носит имя syslockinfo.

Таблица условно имеет четыре поля:

  1. ИД блокирующей сессии SPID;
  2. что именно заблокировано RES ID;
  3. тип блокировки — S,U или X MODE (на самом деле в MS SQL их 22 типа, однако в связки с 1С используется только три);
  4. состояние блокировки — может принимать значение GRANT (установлена) и WAIT (ожидает своей очереди).