Понятие транзакции. Неявные и явные транзакции. Уровни изолированности транзакций в MS SQL Server 2005 и ORACLE 10g. Понятие блокировок. Основные типы блокировок
Понятие блокировок. Основные типы блокировок
Блокировка - это механизм, используемый для управления одновременным доступом к общему ресурсу. Блокирование происходит, когда один сеанс удерживает ресурс, запрашиваемый другим сеансом. В результате запрашивающий сеанс будет заблокирован - он "повиснет" до тех пор, пока удерживающий сеанс не завершит работу с ресурсом.
Оптимистическое блокирование (optimistic locking) - стратегия блокирования набора данных, при которой раздел, содержащий изменяемую запись, блокируется только на время внесения изменений в запись программой, но не пользователем.
Пессимистическое блокирование (pessimistic locking) - стратегия блокирования набора данных, при которой раздел, содержащий изменяемую запись, блокируется на все время внесения изменений в запись пользователем и не доступна для редактирования другим пользователям.
Особенность механизма блокировок Oracle - блокировки данных не хранятся как отдельный ресурс, а содержатся непосредственно в блоках данных. Это позволяет избежать таких проблем, как эскалация блокировок. Ниже перечислены пять основных классов блокировок в Oracle. Первые три - общие (используются во всех базах данных Oracle), а две остальные — только в OPS (Oracle Parallel Server - параллельный сервер).
- Блокировки ЯМД (DML locks). ЯМД означает язык манипулирования данными (Data Manipulation Language), то есть операторы SELECT, INSERT, UPDATE и DELETE. К блокировкам ЯМД относятся, например, блокировки строки данных или блокировка на уровне таблицы, затрагивающая все строки таблицы.
- Блокировки ЯОД (DDL locks). ЯОД означает язык определения данных (Data Definition Language), то есть операторы CREATE, ALTER и так далее. Блокировки ЯОД защищают определения структур объектов.
- Внутренние блокировки (internal locks) и защелки (latches). Защелки - это простые низкоуровневые средства обеспечения последовательности обращений. Защелки обычно запрашиваются системой в режиме ожидания. Это означает, что, если защелку нельзя установить, запрашивающий сеанс приостанавливает работу на короткое время, а затем пытается повторить операцию. Другие защелки могут запрашиваться в оперативном режиме, то есть процесс будет делать что-то другое, не ожидая возможности установить защелку. Защелки выделяются случайным образом. Внутренние блокировки - более сложное средство обеспечения очередности доступа, они позволяют запрашивающему "встать в очередь" в ожидании освобождения ресурса. Запрашивающий защелку сразу уведомляется об освобождении ресурса. В случае внутренней блокировки запрашивающий полностью блокируется.
- Распределенные блокировки (distributed locks). Эти блокировки используются сервером OPS для согласования ресурсов машин, входящих в кластер. Распределенные блокировки устанавливаются экземплярами баз данных, а не отдельными транзакциями.
- Блокировки параллельного управления кэшем (PCM - Parallel Cache Management Locks). Такие блокировки защищают блоки данных в кэше при использовании их несколькими экземплярами баз данных.
SQL Server поддерживает три основных типа блокировок:
- Shared Lock - разделяемая блокировка, которая используется при выполнении операции чтения данных. Позволяется чтение данных другой транзакцией, но запрещено изменение данных.
- Exclusive Lock - монопольная блокировка, которая применяется при изменении данных. Эта блокировка полностью запрещает доступ к данных другим транзакциям.
- Update Lock - блокировка обновления, которая является промежуточной между разделяемой и монопольной блокировкой. Используется, когда транзакция хочет обновить данные в какой-то ближайший момент времени, но не сейчас, и, когда этот момент придет, не хочет ожидать другой транзакции. В этом случае другим транзакциям разрешается устанавливать разделяемые блокировки, но не позволяет устанавливать монопольные.
Блокировки могут устанавливаться на трех уровнях -
- Уровень строк - уровень по умолчанию.
- Уровень страницы - используется для более эффективного использования ресурсов и в случае если в данной странице много строк с этой блокировкой.
- Уровень таблицы - используется при операциях над таблицей и в случае эскалации блокировок.
Взаимоблокировки
Возможна ситуация, когда две транзакции блокируют друг друга так, что продолжение работы не возможно без принудительного завершения одной из транзакций.
Пример:
create table t(i number, j number, s_i varchar2(100), s_j varchar2(100));
Для разрешения подобной ситуации монитор транзакций выбирает одну из транзакций для принудительного завершения.
Практические занятия
Постановка задачи. Проектирование данных на концептуальном и логическом уровнях. Нормализация отношений.
Презентация по ER-моделированию
Подготовка SQL скриптов генерации схемы отношений БД в ERwin. Разработка скрипта для ввода тестовой информации.
Видео-презентация (Для проигрывания требуется Windows Media Player)
Архитектура MS SQL Server 2005. Настройка и использование основных компонент среды. Создание учебной базы данных.
Видео-презентация (Для проигрывания требуется Windows Media Player)
Работа с СУБД MS SQL Server 2005, ORACLE 10g. Примеры соединений с БД, технологии разработки клиенского приложения
Использование технологии Java Database Connectivity (JDBC) для работы с базами данных
Примеры к презентации
SQL-скрипты, проект и исходные коды
package org.mai806.jdbcsample; import java.sql.*; public class QuerySample { public static void main(String[] args) throws Exception { /* ======== Подключение к MS SQL Server ===== */ // Загрузка драйвера Class.forName("com.microsoft.sqlserver.jdbc.SQLServerDriver"); // Соединение с базой данных Connection connection = DriverManager.getConnection( "jdbc:sqlserver://localhost:1433;databaseName=o01;", // localhost - сервер СУБД, o01 - имя базы данных "sa", "123"); // пользователь, пароль /* ======== Подключение к Oracle ============ // Загрузка драйвера Class.forName("oracle.jdbc.OracleDriver"); // Соединение с базой данных Connection connection = DriverManager.getConnection( "jdbc:oracle:thin:@localhost:1521:orcl", // localhost - сервер СУБД, orcl - SID базы оракла "o01", "o01"); // пользователь, пароль // Создание Statement PreparedStatement stmt = connection.prepareStatement ("select ID, NAME from PERSON where NAME like ?"); stmt.setString(1, "%S%"); // Выполнение запроса ResultSet rs = stmt.executeQuery(); // Перебор результата выполнения запроса while(rs.next()) { // Пример выбора параметра по номеру или по имени System.out.println("ID: " + rs.getLong(1) + "; NAME="+ rs.getString("NAME")); } // закрытие использованных ресурсов БД rs.close(); stmt.close(); connection.close(); } }Листинг P.1. Выполнение запроса: QuerySample.java
package org.mai806.jdbcsample; import java.sql.*; import java.util.ResourceBundle; public class StoredProcedureSample { private static Connection connection = null; public static void main(String[] args) throws Exception { // Получение соединения из значений параметров в файле properties ResourceBundle properties = ResourceBundle.getBundle("database"); Class.forName(properties.getString("driver")); connection = DriverManager.getConnection( properties.getString("url"), properties.getString("user"), properties.getString("password")); transferAmount(1,2,100.0); connection.close(); } /** * Переводит указанную сумму с одного счета на другой * @param from счет плательщика * @param to счет получателя * @param amount сумма */ public static void transferAmount(long from, long to, double amount) throws Exception { // Создание Statement CallableStatement stmt = connection.prepareCall("{call TransferAmount(?,?,?)}"); // Установка параметров stmt.setLong(1, from); stmt.setLong(2, to); stmt.setDouble(3, amount); // Выполнение процедуры stmt.execute(); } }Листинг P.2. Выполнение хранимой процедуры: StoredProcedureSample.java
package org.mai806.jdbcsample; import java.sql.*; import java.util.ResourceBundle; public class TransactionalSample { private static Connection connection = null; public static void main(String[] args) throws Exception { // Получение соединения из значений параметров в файле properties ResourceBundle properties = ResourceBundle.getBundle("database"); Class.forName(properties.getString("driver")); connection = DriverManager.getConnection( properties.getString("url"), properties.getString("user"), properties.getString("password")); // Ручное управление транзакциями connection.setAutoCommit(false); try { transferAmount(2, 1, 10.0); } finally { connection.close(); } } /** * Переводит указанную сумму с одного счета на другой * @param from счет плательщика * @param to счет получателя * @param amount сумма */ public static void transferAmount(long from, long to, double amount) throws Exception { PreparedStatement stmt = null; Statement query = null; try { stmt = connection.prepareStatement ("update ACCOUNT set AMOUNT=AMOUNT+? where ID=?"); // Забираем сумму со счета плательщика stmt.setDouble(1, -amount); stmt.setLong(2, from); stmt.execute(); // Добавляем сумму на счет получателя stmt.setDouble(1, amount); stmt.setLong(2, to); stmt.execute(); // Пост-проверка: отрицательность счета плательщика query = connection.createStatement(); ResultSet rs = query.executeQuery( "select AMOUNT from ACCOUNT where ID="+from+" and AMOUNT<0"); if (rs.next()) { throw new Exception("На счете №"+from+" недосточно средств ["+(amount+rs.getDouble(1))+"] для снятия суммы ["+amount+"]"); } connection.commit(); System.out.println("Перечисление средств успешно выполнено"); } catch(Exception e) { e.printStackTrace(); connection.rollback(); } finally { if (stmt!=null) stmt.close(); if (query!=null) query.close(); } } }Листинг P.3. Работа с транзакциями: TransactionalSample.java