Опубликован: 11.03.2009 | Уровень: специалист | Доступ: свободно
Лекция 11:
Триггеры. Основные понятия. Типы триггеров. Общая схема активизации триггеров
Использование предикатов inserting, ... и new, old
drop table test_log;
create table test_log(op_user varchar2(100),
op_date date, i integer, s varchar2(100));
create or replace trigger t_ud
before update of i, s or delete
on test
for each row
begin
if updating('s') then
if :new.s > :old.s then
raise_application_error(-20000, 'update error');
end if;
elsif deleting then
insert into test_log values(user, sysdate, :old.i, :old.s);
end if;
end;Выполнение триггреров в той же транзакции
delete from test; select * from test_log; rollback; select * from test_log;
Активизация и деактивизация триггеров
alter trigger t_ud disable; alter table test enable all triggers;
Получение информации о триггерах
select * from user_triggers; select * from user_objects;
Запрет изменения new, old в after ... и table level триггерах
create or replace trigger ta_ud
after update
on test
for each row
begin
:new.s := 'aaaaaaa';
end;
create or replace trigger ta_ud
before update
on test
for each row
begin
:old.s := 'aaaaaaa';
end;
create or replace trigger tb_ud
before update
on test
begin
:new.s := 'aaaaaaa';
end;Несколько триггеров одного типа
create or replace trigger ta_ud1
after update
on test
for each row
begin
dbms_output.put_line('trigger update 1');
end;
create or replace trigger ta_ud2
after update
on test
for each row
begin
dbms_output.put_line('trigger update 2');
end;Использование исключений
create or replace package p_exc
as
invalid_str exception;
end;
create or replace trigger t_ui
before insert or update
on test
for each row
begin
if :new.s < 'c' then
raise p_exc.invalid_str;
end if;
end;
begin
delete from test;
commit;
insert into test values(1, 'aaa');
exception
when p_exc.invalid_str then
dbms_output.put_line
('invalid_str: ' || sqlcode || ' ' || sqlerrm);
end;Триггеры instead of
create table tp(i integer primary key);
create table tc(k integer primary key, i integer references tp(i));
begin
commit;
delete from tc;
delete from tp;
commit;
insert into tp values(1);
insert into tp values(2);
insert into tc values(5, 1);
insert into tc values(6, 1);
insert into tc values(7, 2);
commit;
end;
create or replace view v as select tp.i ii, tc.k kk from
tp inner join tc on tp.i = tc.i;
select * from user_updatable_columns where table_name = 'V';
create or replace trigger vt
instead of insert
on v
for each row
declare
ii integer;
begin
begin
select i into ii from tp where i = :new.ii;
exception
when no_data_found then
insert into tp(i) values(:new.ii);
end;
update tc set i = :new.ii where k = :new.kk;
if sql%rowcount = 0 then
insert into tc(k, i) values(:new.kk, :new.ii);
end if;
end;Изменяющиеся таблицы
create table grp(gn number primary key, gname varchar2(10)); create table std(sn number primary key, gn number references grp, sname varchar2(100));
При добавлении группы студента в группу с максимальным кол-вом студентов, перенаправляем его в группу с минимальным кол-вом студентов
create or replace trigger std_i_a
after insert
on std
for each row
declare
n number;
begin
dbms_output.put_line('OK insert after');
select count(*) into n from std where gn = :new.gn;
dbms_output.put_line('n = ' || n);
end;
create or replace trigger std_i_b
before insert
on std
for each row
declare
n number;
begin
dbms_output.put_line('OK insert before');
select count(*) into n from std where gn = :new.gn;
dbms_output.put_line('n = ' || n);
end;
create or replace trigger std_i_a_all
after insert
on std
declare
n number;
begin
dbms_output.put_line('OK insert after all');
select count(*) into n from std;
dbms_output.put_line('n = ' || n);
end;
create or replace trigger std_i_b_all
before insert
on std
declare
n number;
begin
dbms_output.put_line('OK insert before all');
select count(*) into n from std;
dbms_output.put_line('n = ' || n);
end;Практические занятия
Постановка задачи. Проектирование данных на концептуальном и логическом уровнях. Нормализация отношений.
Презентация по 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