27
СУБД Лекция 4 Павел Щербинин

СУБД 2013 Лекция №4 "Расширенные возможности работы с базами данных. Триггеры и хранимые процедуры"

Embed Size (px)

Citation preview

СУБД

Лекция 4

Павел Щербинин

Хранимые процедуры

CREATE

[DEFINER = { user | CURRENT_USER }]

PROCEDURE sp_name ([proc_parameter[,...]])

[characteristic ...] routine_body

CREATE

[DEFINER = { user | CURRENT_USER }]

FUNCTION sp_name ([func_parameter[,...]])

RETURNS type

[characteristic ...] routine_body

proc_parameter:

[ IN | OUT | INOUT ] param_name type

func_parameter:

param_name type

Хранимые процедуры

characteristic:

COMMENT 'string'

| LANGUAGE SQL

| [NOT] DETERMINISTIC

| {

CONTAINS SQL

| NO SQL

| READS SQL DATA

| MODIFIES SQL DATA

}

| SQL SECURITY { DEFINER | INVOKER }

routine_body:

Valid SQL routine statement

Хранимые процедуры ЗА

Разделение логики с другими приложениями. Хранимые процедуры инкапсулируют функциональность; это обеспечивает связность доступа к данным и управления ими между различными приложениями.

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

Обеспечивает механизм защиты.

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

Хранимые процедуры ПРОТИВ

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

• Дублирование логики своего приложения в двух местах: серверный код и код для хранимых процедур, тем самым усложняя процесс манипулирования данными.

• Миграция с одной СУБД на другую (DB2, SQL Server и др.) может привести к проблемам.

Хранимые процедуры ПРИМЕР

DELIMITER //

DROPPROCEDUREIF EXISTS p1//

CREATE PROCEDURE `p1` ()

LANGUAGE SQL

DETERMINISTIC

SQL SECURITY DEFINER

COMMENT 'A procedure'

BEGIN

SELECT 'Hello World !';

END//

CALL p1();

Хранимые процедуры ПРИМЕР

DELIMITER //

CREATE PROCEDURE `var_proc` (IN paramstr VARCHAR(20))

BEGIN

DECLARE a, b INT DEFAULT 5;

DECLARE str VARCHAR(50);

DECLARE today TIMESTAMP DEFAULT CURRENT_DATE;

DECLARE v1, v2, v3 TINYINT;

INSERT INTO table1 VALUES (a);

SET str = 'I am a string';

SELECT CONCAT(str,paramstr), today FROM table2 WHERE

b >=5;

END //

Хранимые процедуры

УСЛОВИЯ

IF search_condition THEN statement_list

[ELSEIF search_condition THEN statement_list] ...

[ELSE statement_list]

END IF

CASE case_value

WHEN when_value THEN statement_list

[WHEN when_value THEN statement_list] ...

[ELSE statement_list]

END CASE

CASE

WHEN search_condition THEN statement_list

[WHEN search_condition THEN statement_list] ...

[ELSE statement_list]

END CASE

Хранимые процедуры

LOOP

[begin_label:] LOOP

statement_list

END LOOP [end_label]

CREATE PROCEDURE doiterate(p1 INT)

BEGIN

label1: LOOP

SET p1 = p1 + 1;

IF p1 < 10 THEN

ITERATE label1;

END IF;

LEAVE label1;

END LOOP label1;

SET @x = p1;

END;

Хранимые процедуры

REPEAT, WHILE[begin_label:] REPEAT

statement_list

UNTIL search_condition

END REPEAT [end_label]

[begin_label:] WHILE search_condition DO

statement_list

END WHILE [end_label]

CREATE PROCEDURE dowhile()

BEGIN

DECLARE v1 INT DEFAULT 5;

WHILE v1 > 0 DO

...

SET v1 = v1 - 1;

END WHILE;

END;

Хранимые процедуры

HANDLER

DECLARE handler_action HANDLER

FOR condition_value [, condition_value] ...

statement

handler_action:

CONTINUE

| EXIT

| UNDO

condition_value:

mysql_error_code

| SQLSTATE [VALUE] sqlstate_value

| condition_name

| SQLWARNING

| NOT FOUND

| SQLEXCEPTION

Хранимые процедуры

КУРСОРЫDECLARE cursor-name CURSOR FOR SELECT ...;

OPEN cursor-name;

FETCH cursor-name INTO variable [, variable];

CLOSE cursor-name;

Declare vBankId integer;

Declare vBankName VARCHAR(50);

Declare vAddress VARCHAR(50);

Declare done integer default 0;

Declare BankCursor Cursor for

Select`bank`.`BankId`,`bank`.`BankName`,`bank`.`Address` FROM

`bank`;

DECLARE CONTINUE HANDLER FOR SQLSTATE '02000' SET done=1;

Open BankCursor;

WHILE done = 0 DO

FETCH BankCursor INTO vBankId,vBankName,vAddress;

END WHILE;

Close BankCursor;

Хранимые процедуры

EXECUTEEXECUTE stmt_name [USING @var_name [, @var_name] ...]

DELIMITER $$

DROP PROCEDURE IF EXISTS `create_archive`$$

CREATE PROCEDURE `create_archive`(IN current_table VARCHAR(50))

BEGIN

DECLARE template,archive_template VARCHAR(50);

SET archive_template=replace(curdate(),"-","");

SET template=CONCAT(current_table,"_",archive_template);

SET @archive_query:=CONCAT("CREATE TABLE ",template,"

ENGINE=ARCHIVE AS

(SELECT * FROM ",current_table," )");

PREPARE archive_query FROM @archive_query;

EXECUTE archive_query;

DEALLOCATE PREPARE archive_query;

END$$

Триггеры

CREATE

[DEFINER = { user | CURRENT_USER }]

TRIGGER trigger_name trigger_time trigger_event

ON tbl_name FOR EACH ROW trigger_body

trigger_time = BEFORE | AFTER

trigger_event = INSERT | UPDATE | DELETE

Триггеры (Пример)

CREATE TRIGGER

add_count_comment

AFTER INSERT ON comments

FOR EACH ROW BEGIN

UPDATE

user

SET

user.countcomment=user.countcomment+1

WHERE

user.id = NEW.user_id;

Триггеры (Пример)

CASE NEW.owner_name

WHEN 'Blog' THEN

UPDATE blog

SET comment = comment+1

WHERE id = NEW.owner_id ;

WHEN 'Article' THEN

UPDATE article

SET comment = comment+1

WHERE id = NEW.owner_id ;

WHEN 'PopulatePlace' THEN

UPDATE populate_place

SET comment = comment+1

WHERE id = NEW.owner_id ;

END CASE;

Триггеры (Пример)

CASE NEW.owner_name

WHEN 'Blog' THEN

SET usertitle = (

select title from blog where id=NEW.owner_id

);

WHEN 'Article' THEN

SET usertitle = (

select title from article where id=NEW.owner_id

);

WHEN 'PopulatePlace' THEN

SET usertitle = '';

END CASE;

INSERT INTO user_has_events VALUES (NEW.user_id, NEW.id,

"Comments", NOW() , usertitle );

END

Транзакции

• START TRANSACTION

• COMMIT

• ROLLBACK

Транзакции

START TRANSACTION;

SELECT balance FROM checking WHERE customer_id

= 10233276;

UPDATE checking SET balance = balance - 200.00

WHERE customer_id = 10233276;

UPDATE savings SET balance = balance + 200.00

WHERE customer_id = 10233276;

COMMIT;

ACID

• Atomicity (Атомарность)Транзакция должна функционировать как единая неделимая еденица работы таким образом, чтобы вся транзакция была либо выполнена, либо отменена.

• Consistency (Непротиворечивость)База данных должна всегда переходить из одного непротиворечивого состояния в последующее.

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

• Durability (Долговечность)Будучи зафиксированы, внесенные в ходе транзакции изменения становятся постоянными. Это означает, что изменения должны быть записаны так, чтобы данные не могли быть потеряны в случае сбоя системы.

Уровни изоляции

Уровень изоляции

Возможность чернового чтения

Возможность невоспроизводимого чтения

Возможность фантомного чтения

Блокировка чтения

READ UNCOMMITTED Да Да Да Нет

READ COMMITTED Нет Да Да Нет

REPEATABLE READ Нет Нет Да Нет

SERIALIZABLE Нет Нет Нет Да

Уровни изоляции

Уровень изоляции

Возможность чернового чтения

Возможность невоспроизводимого чтения

Возможность фантомного чтения

Блокировка чтения

READ UNCOMMITTED Да Да Да Нет

READ COMMITTED Нет Да Да Нет

REPEATABLE READ Нет Нет Да Нет

SERIALIZABLE Нет Нет Нет Да

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

Транзакция #1

START TRANSACTION;

UPDATE StockPrice SET close = 45.50 WHERE stock_id = 4 and date =

2002-05-01;

UPDATE StockPrice SET close = 19.80 WHERE stock_id = 3 and date =

2002-05-02;

COMMIT;

Транзакция #2

START TRANSACTION;

UPDATE StockPrice SET high = 20.12 WHERE stock_id = 3 and date =

2002-05-02;

UPDATE StockPrice SET high = 47.20 WHERE stock_id = 4 and date =

2002-05-01;

COMMIT;

Ручные блокировки

SELECT ... FOR UPDATE;

SELECT ... LOCK IN SHARE MODE;

LOCK TABLES

tbl_name [[AS] alias] lock_type

[, tbl_name [[AS] alias] lock_type] ...

lock_type:

READ [LOCAL]

| [LOW_PRIORITY] WRITE

UNLOCK TABLES

MVCC

SELECTПодсистема InnoDB должна проверить каждую строку, чтобы убедиться, что она отвечает двум критериям:• InnoDB должна найти версию строки, которая по крайней мере такая же старая, как версия транзакции (то есть ее номер версии должен быть меньше или равен номеру версии транзакции). Это гарантирует, что либо строка существовала до начала транзакции, либо транзакция создала или изменила эту строку.• Версия удаления строки должна быть не определена или ее значение больше, чем версия транзакции. Это гарантирует, что строка не была удалена до начала транзакции.INSERTInnoDB записывает текущий системный номер версии вместе с новой строкой.DELETEInnoDB записывает текущий системный номер версии как идентификатор удаления строки.UPDATEInnoDB создает новую копию строки, используя системный номер версии в качестве версии новой строки. Она также записывает системный номер версии как версию удаления старой строки.

Конкуренция

Стратегия блокировки Конкуренция

Накладные расходы

Подсистемы хранения

Уровень таблицы Самая низкая Самые низкие

MyISAM, Merge, Memory

Уровень строки Высокая Высокие NDB ClusterУровень строки с MVCC Самая высокая Самые высокие

InnoDB, Falcon, PBXT, solidDB

Спасибо за вниманиеПавел Щербинин

[email protected]