powered by simpleCommunicator - 2.0.60     © 2026 Programmizd 02
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Форумы / Проектирование БД [игнор отключен] [закрыт для гостей] / Задача для версионника
25 сообщений из 123, страница 2 из 5
Задача для версионника
    #32826815
gardenman
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Решение:
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
80.
81.
82.
83.
84.
85.
86.
87.
88.
89.
90.
91.
92.
93.
94.
95.
96.
97.
98.
99.
100.
101.
102.
103.
104.
105.
106.
107.
108.
109.
110.
111.
112.
113.
114.
115.
116.
117.
118.
119.
120.
121.
122.
123.
124.
125.
126.
127.
128.
129.
130.
131.
132.
133.
134.
135.
136.
137.
138.
139.
140.
141.
142.
143.
144.
145.
146.
147.
148.
149.
150.
151.
152.
153.
154.
155.
156.
157.
158.
159.
160.
161.
162.
163.
connect to test@

-----------------------------------------------------------------------
--  Расписание движения поездов
-----------------------------------------------------------------------
--  route_num       рейс
--  departure_dt    дата отправления
--  ticket_cnt      количество билетов (всего)
--  ticket_sold     количество проданных билетов
--
create table routes (
    route_num       char( 5 ) not null,
    departure_dt    date not null,
    tickets_cnt     integer not null,
    tickets_sold    integer,
    constraint AtCnt
        check((tickets_cnt>=tickets_sold) or (tickets_sold is null)),
    constraint AtRoute_PK
        primary key (route_num,departure_dt)
)
@

-----------------------------------------------------------------------
--  Проданные билеты
-----------------------------------------------------------------------
--  route_num       рейс
--  departure_dt    дата отправления
--  tickets_sold    количество проданых билетов
--  desk            номер кассы
--  ts              дата продажи
create table sales (
    route_num       char( 5 ) not null,
    departure_dt    date not null,
    tickets_sold    integer check (tickets_sold> 0 ),
    desk            integer not null,
    ts              timestamp,
    constraint AtRoute_FK foreign key (route_num,departure_dt)
        references routes (route_num,departure_dt) on delete restrict
)
@

create index ISaleDesk
    on sales (desk,ts) allow reverse scans
@

create unique index ISaleRoutes
    on sales (route_num,departure_dt,desk,ts) allow reverse scans
@

---------------------------------------------------------------------
--  Блокировки на билеты
---------------------------------------------------------------------
--  route_num       char(5) not null,
--  departure_dt    date not null,
--  ticket_lock     integer check (ticket_sold>0),
--  desk            integer
create table locks (
    route_num       char( 5 ) not null,
    departure_dt    date not null,
    tickets_lock    integer check (tickets_lock> 0 ),
    desk            integer,
    constraint AtRouteI_FK foreign key (route_num,departure_dt)
        references routes (route_num,departure_dt) on delete restrict
)
@
create unique index ILock
    on locks (route_num,departure_dt,desk) allow reverse scans
@
create unique index ILockDesk
    on locks (desk,route_num,departure_dt) allow reverse scans
@

echo ---------------------------@
echo Заливаем расписание поездов@    
echo ---------------------------@
@
insert into routes
    (route_num,departure_dt,tickets_cnt,tickets_sold)
values
    ('C100',date('25.12.2004'), 1000 , 0 ),
    ('C100',date('26.12.2004'), 1000 , 0 ),
    ('C100',date('27.12.2004'), 1000 , 0 ),
    ('C100',date('28.12.2004'), 1000 , 0 ),
    ('C100',date('29.12.2004'), 1000 , 0 ),
    ('C100',date('30.12.2004'), 1000 , 0 ),
    ('C100',date('31.12.2004'), 1000 , 0 )
@
commit@

select * from routes@

--------------------------------------------------------------
-- Триггер, проверяющий, что есть еще незаблокированные билеты
-- которые можно продать или заблокировать для продажи
--------------------------------------------------------------
create trigger BILocks 
no cascade before insert on locks
referencing new as N
for each row
when
(
    N.tickets_lock
    >
    (select
        routes.tickets_cnt-routes.tickets_sold-
        coalesce((
            select sum(tickets_lock) from locks
                where locks.route_num=N.route_num
                        and locks.departure_dt=N.departure_dt
        ), 0 )
    from
        routes
    where
        routes.route_num=N.route_num
        and routes.departure_dt=N.departure_dt
    )
)
    signal sqlstate '75001' set message_text='Too many tickets'
@
commit@

------------------------------------------------------------
-- Продаем именно столько билетов, сколько заблокировали
------------------------------------------------------------
create trigger BISales
no cascade before insert on sales
referencing new as N
for each row
begin atomic
    set (N.tickets_sold,N.desk,N.ts)=(
        select
            tickets_lock,
            desk,
            current timestamp
        from
            locks
        where
            locks.route_num=N.route_num
            and locks.departure_dt=N.departure_dt
                and locks.desk=N.desk
        );
end
@
commit@

----------------------------------------------------------
-- После того как все продано увеличиваем кол-во проданных
-- билетов в расписании и снимаем блокировку с билетов
----------------------------------------------------------
create trigger AISales
after insert on sales
referencing new as N
for each row
begin atomic
    update routes
        set tickets_sold=tickets_sold+N.tickets_sold
            where routes.route_num=N.route_num
                    and routes.departure_dt=N.departure_dt;
    delete from locks
        where locks.desk=N.desk;
end
@
commit@
...
Рейтинг: 0 / 0
Задача для версионника
    #32826816
gardenman
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
причем работа проходит в режиме Uncommited Read (грязное чтение)
...
Рейтинг: 0 / 0
Задача для версионника
    #32826826
Фотография Александр Гoлдун
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
gardenman Можно поработать на складе. Предположим у нас есть 100 ящиков какого-то товара. И в разных филиалах его продают. сначала - оформление документов (выписка фсяких накладных и пр...). И чтоб пока документы оформляются - наши ящики не ушли кому-нить другому. Все - одной транзакцией.
В общем - условия - те же...

Бред. При чем здесь транзакции? Не видел ни одного заказчика, который описывая
требования к системе упомянул бы условие "Все - одной транзакцией".

А вот условие "что бы ящики не ушли" решается элементарно при правильном
проектировании. Например введением понятия "резервирование", которое
может происходить еще до выписки документов.

--
http://talk.ru/forum/talk.ru.accounting.development
...
Рейтинг: 0 / 0
Задача для версионника
    #32826836
gardenman
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
системы всякие бывают...)) требования разные... но подходы к решению проблем могут быть одними и теми же...
...
Рейтинг: 0 / 0
Задача для версионника
    #32826841
Серега
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Ты зря не привел скрипт создания инстанса с включением в пост всех скриптов Оракла. Было бы нагляднее.

Ответь мне на вопрос - а где учет мест? Ведь тому мужику, что насилует кассиршу, надо плацкартные НЕБОКОВЫЕ. А если их назавтра нет, то он поедет послезавтра.

причем работа проходит в режиме Uncommited Read (грязное чтение)
Ты мне просто скажи - на каком вокзале это работает? В каком городе? А то вдруг я туда поеду. Предупрежден - уже вооружен.
...
Рейтинг: 0 / 0
Задача для версионника
    #32826850
Фотография softy
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Вы еще про бронирование забыли. Это когда деньги еще не уплачены, а билеты уже формально проданы (то есть их нет в наличии в кассе).

Значит ли это с точки зрения автора топика, что транзакция закончится только когда человек придёт и выкупит билеты реально.
...
Рейтинг: 0 / 0
Задача для версионника
    #32826916
Фотография Журавлев Денис
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
gardenmanсистемы всякие бывают...)) требования разные... но подходы к решению проблем могут быть одними и теми же...
Странная задача на самом деле.
В начале вы намекаете что сущьность места не нужна (едем в электричке?) достаточно кол-ва свободных мест в поезде, а потом очень долго забиваете паспортные данные (куда?).
Т.е. система учитывает сколько свободных мест и какие паспорта едут в этом поезде?
...
Рейтинг: 0 / 0
Задача для версионника
    #32826944
gardenman
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
))) Ну уж нет, раздувать простой пример до решения для МПС я не намерен...))
так что решение с плацкартом и СВ с девушкой для Сереги - предоставим кому-нить другому.
Ладно, более подробно, как это все работает:
1) К 1 окошку подходит гражданин и заказывает 600 билетов
set isolation ur
insert into locks values ('C100','31.12.2004',600,1)
DB20000I Команда SQL выполнена успешно.

гражданин сует кучу паспортов, бабки и ждет когда его оформят по полной программе.
2) Ко 2 окошку подходит другой гражданин и пытается заказать 500 билетов:
set isolation ur
insert into locks values ('C100','31.12.2004',600,2)
SQL0438N Программа генерирует ошибку с текстом диагностики: "Too many
tickets". SQLSTATE=75001

Срабатывает триггер BILocks, мэн получает отлуп по полной программе и уходит, а к окошку подходит следующий
и заказывает 4 билета
insert into locks values ('C100','31.12.2004',4,2)
DB20000I Команда SQL выполнена успешно.

--от автора:
Код: plaintext
1.
2.
3.
4.
5.
6.
db2 => select * from locks
ROUTE_NUM DEPARTURE_DT TICKETS_LOCK DESK
--------- ------------ ------------ -----------
C100       31 . 12 . 2004              600             1 
C100       31 . 12 . 2004                4             2 
   2  записей выбрано.

3) во втором окошке все напечатали, бабки приняли и делается:

insert into sales (route_num,departure_dt,desk) values ('C100','31.12.2004',2)
commit

срабатывает триггер BISales, чтобы продать именно столько билетов сколько было заблокировано и срабатывает триггер AISales, который обновляет кол-во проданных билетов в routes. Тут же делается commit, поэтому таблица routes не блокируется надолго. А блокировки в таблице locks от 2 окошка на 4 билета снимается.
--от автора

Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
db2 => select * from locks

ROUTE_NUM DEPARTURE_DT TICKETS_LOCK DESK
--------- ------------ ------------ -----------
C100       31 . 12 . 2004              600             1 

   1  записей выбрано.

db2 => select * from sales

ROUTE_NUM DEPARTURE_DT TICKETS_SOLD DESK        TS
--------- ------------ ------------ ----------- --------------------------
C100       31 . 12 . 2004                4             2   2004 - 12 - 14 - 15 . 21 . 26 . 515000 

   1  записей выбрано.

db2 => select * from routes

ROUTE_NUM DEPARTURE_DT TICKETS_CNT TICKETS_SOLD
--------- ------------ ----------- ------------
C100       25 . 12 . 2004            1000              0 
C100       26 . 12 . 2004            1000              0 
C100       27 . 12 . 2004            1000              0 
C100       28 . 12 . 2004            1000              0 
C100       29 . 12 . 2004            1000              0 
C100       30 . 12 . 2004            1000              0 
C100       31 . 12 . 2004            1000              4 

   7  записей выбрано.

а в это время в 1 окошке все еще незаконченная транзакция по продаже 600 билетов все еще висит, нужное кол-во билетов блокировано... а тем временем 2 окошко может обслуживать следующего потенциального пассажира.
...
Рейтинг: 0 / 0
Задача для версионника
    #32826948
gardenman
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
теперь можете критиковать....
...
Рейтинг: 0 / 0
Задача для версионника
    #32826987
Серега
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
gardenman))) Ну уж нет, раздувать простой пример до решения для МПС я не намерен...))
Так ты для детской пластмассовой ЖД что ли? Тогда пойдет.

gardenmanтак что решение с плацкартом и СВ с девушкой для Сереги - предоставим кому-нить другому.
Вот так всегда.

gardenman1) К 1 окошку подходит гражданин и заказывает 600 билетов
set isolation ur
insert into locks values ('C100','31.12.2004',600,1)
DB20000I Команда SQL выполнена успешно.

гражданин сует кучу паспортов, бабки и ждет когда его оформят по полной программе.
После ввода 599 паспортов система вешается и "спасает" ситуацию только комбинация из трех пальцев. В системе благополучно залочено 600 мест.
...
Рейтинг: 0 / 0
Задача для версионника
    #32826993
gardenman
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
увы... транзакция благополучно откатится.
...
Рейтинг: 0 / 0
Задача для версионника
    #32827004
Фотография tygra
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Поддерживаю Серегу :)

И еще:
автора в это время в 1 окошке все еще незаконченная транзакция по продаже 600 билетов все еще висит, нужное кол-во билетов блокировано...
Объясните, зачем вам тут транзакция??? Общая, одна на все 600 билетов, зачем? Вы что, по-человечески, без транзакции, не можете спокойно зарезервировать 600 билетов для пластмассовой ЖД и потом оформлять их хоть три дня подряд?

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

Круто!

-- Tygra's --
...
Рейтинг: 0 / 0
Задача для версионника
    #32827014
Фотография tygra
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Ну я надеюсь, судя по всему, что Экспресс-2 (и 3) не по такой схеме делали, иначе бы вокзал дневное количество билетов месяц продавал бы

-- Tygra's --
...
Рейтинг: 0 / 0
Задача для версионника
    #32827618
iLLer
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Опять никто никого не понял... Или я никого не понял, но сделал следующие выводы:
1) Разделить понятия транзакций с СУБД и транзакций с кассиршой
2) Таблица с блокировками - кривая система резервирования

Блокировки допустимы только во время проведения операций с базой. Взятие денег, ввод данных - не операция с базой, а операция с клиентом.
Блокировки нужны более высшего уровня.
Операция резервирования и операция реализации лежат в одной таблице, которая привязана к таблице с рейсами. Их различие ведется по статусу. На кол-во свободных мест стоит ограничение >0. Если кто-то захочит вставить лишнее - не выйдет. Сначала добавляем икс билетов в расход со статусом зарезервировано, триггером снимаем этот икс с таблицы со свободными местами. Затем кассир вбивает свою муть получает деньги и переводит статус в продано. Если при срабатывании триггера срабатывает ограничение, то кассир обламается с резервированием - и вбивать ничего не придется. Если клиентский комп отвалился, то тетка решает, вешать ли ей табличку "технический перерыв", то ли ждать разрешения проблемы связи. При возобновлении связи в первом случае она удаляет резерв, во втором доводит дело до конца.
Если необходим учет разновидности мест(товарной сущности), то это надо соответственно отразить в предложенном варианте.
Почему все бьются над одной и той же проблемой, и все время призывают в помощь уровни изоляции???!! И лень поискать на форуме. Здесь уже обсуждался похожий пример, только там был склад и выписывание товара, что по сути одно и тоже. Ссылку не дам, лень искать. Думайте, господа, над сущностью телодвижений "клиентов" и их взаимосвязью.
...
Рейтинг: 0 / 0
Задача для версионника
    #32828073
Фотография tygra
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
2 iLLer
Правильно все понял - мы о том же и говорим с Серегой.


-- Tygra's --
...
Рейтинг: 0 / 0
Задача для версионника
    #32828075
gardenman
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
"Усиленное решение".
Я так понимаю единственная проблема была в триггере BILocks, дескать он может сработает не совсем так как нужно в конкурентной среде. Т.е. Я и Ёжик намекал на то, что всеже могут быть проданы лишние билеты (особенно если убрать CHECK CONSTRAINT AtCnt на таблице ROUTES).
Конечно же я осознаю, что то, что сейчас здесь будет нарисовано не будет работать ни на одной из известных мне баз кроме DB2.
Напишем хранимую процедуру на С++ в которой создадим именнованный мьютекс. Таким образом получится что инсертить в таблицу LOCKS (вместе со срабатыванием соответствующего триггера BILocks) в один момент времени может только один клиент.

Makefile
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
DBNAME=test
DBUSER=db2admin
DBPASSWORD=ibmdb2

TARGET=reserve.dll
DEF=reserve.def
LIBS=db2api.lib

CPPOBJS=reserve.obj
CFLAGS= -Z7 -O2 -G5 -c -W2 -D_X86_= 1  -DWIN32 -GR -GX
LINKFLAGS= /DEBUG /DLL

.SUFFIXES:
.SUFFIXES: .obj .sqx .cpp

.cpp.obj:
	cl $(CFLAGS) $*.cpp

.sqx.obj:
	echo CONNECT TO $(DBNAME) USER $(DBUSER) USING '$(DBPASSWORD)' > $*.db2
	echo PREP $*.sqx BINDFILE >> $*.db2
	echo BIND $*.bnd >> $*.db2
    @if exist $*.log del $*.log
    d:\sqllib\bin\db2clpex db2 -z $*.log -vf $*.db2
    type $*.log
	cl $(CFLAGS) $*.cxx

$(TARGET): $(CPPOBJS) Makefile $(DEF)
	link $(LINKFLAGS) -out:$(TARGET) $(SQXOBJS) $(CPPOBJS) $(LIBS) -def:$(DEF)
    copy $(TARGET) d:\sqllib\function

reserve.def
Код: plaintext
1.
2.
LIBRARY reserve
EXPORTS reserve

reserve.sqx
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include <windows.h>
#include <sqlenv.h>
#include <sqludf.h>

#define CREATE_MUTEX  1 
#define RELEASE_MUTEX  0 

SQL_API_RC SQL_API_FN reserve (
	char *pRoute_Num,
    char *pDeparture_Dt,
    sqlint32 *pTickets_Lock,
    sqlint32 *pDesk
)
{
	struct sqlca sqlca;
    EXEC SQL BEGIN DECLARE SECTION;
		char (*pRN)[ 5 + 1 ]  = (char(*)[ 5 + 1 ])pRoute_Num;
	    char (*pDT)[ 10 + 1 ] = (char(*)[ 10 + 1 ])pDeparture_Dt;
    	sqlint32& pTL     = *pTickets_Lock;
        sqlint32& pD      = *pDesk;
    EXEC SQL END DECLARE SECTION;

	HANDLE h=CreateMutex(NULL,FALSE,"Locker");
    if (h==NULL) {
    	strcpy(sqlca.sqlstate,"75001");
        return  0 ;
    }
    DWORD rc=WaitForSingleObject(h,INFINITE);
   	switch(rc) {
    case WAIT_OBJECT_0:
    	break;
    case WAIT_FAILED:
    case WAIT_ABANDONED:
    case WAIT_TIMEOUT:
	default:
   		CloseHandle(h);
    	strcpy(sqlca.sqlstate,"75002");
        return  0 ;
    }

    EXEC SQL INSERT INTO LOCKS
    	(ROUTE_NUM,DEPARTURE_DT,TICKETS_LOCK,DESK)
        VALUES (:pRN,:pDT,:pTL,:pD) WITH UR;

    ReleaseMutex(h);
   	CloseHandle(h);

	if (SQLCODE) {
    	pTL=- 1 ;
    }
	return  0 ;
}



Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
80.
81.
82.
83.
84.
85.
86.
87.
88.
89.
90.
91.
92.
93.
94.
95.
96.
97.
98.
99.
100.
101.
102.
103.
104.
105.
106.
107.
108.
109.
110.
111.
112.
113.
114.
115.
116.
117.
118.
119.
120.
121.
122.
connect reset@
connect to test@

drop procedure reserve(char( 5 ),date,integer,integer)@


create procedure reserve(
	in Route char( 5 ),
    in Departure date,
    inout TicketsCnt integer,
    in Desk integer
)
modifies sql data
not deterministic
language c
external name 'reserve!reserve'
fenced threadsafe
no external action
parameter style db2sql
@

----------------------------------------------------
-- небольшое тестирование производительности
----------------------------------------------------
create procedure testrs(inout start timestamp,inout stop timestamp) 
language sql
begin
	declare desk integer default  1000 ;
    declare cnt integer default  1 ;
    set start=current timestamp;
    while desk> 0  do
    	call reserve('C100',cast('25.12.2004' as date),cnt,desk);
        set desk=desk- 1 ;
    end while;
    set stop=current timestamp;
end
@

quit@

=================================================
-- Результаты выполнения
=================================================

db2 => call testrs(NULL,NULL)

  Value of output parameters
  --------------------------
  Parameter Name  : START
  Parameter Value :  2004 - 12 - 15 - 02 . 27 . 00 . 937003 

  Parameter Name  : STOP
  Parameter Value :  2004 - 12 - 15 - 02 . 27 . 03 . 531000 

  Return Status =  0 

db2 => select count(*) from locks

 1 
-----------
        1000 

   1  record(s) selected.

db2 => rollback
DB20000I  The SQL command completed successfully.
db2 => select count(*) from locks

 1 
-----------
           0 

   1  record(s) selected.

db2 =>



-------------------------------------------------
-- блокируем 200 билетов в 1 окошке
-------------------------------------------------
db2 => set isolation ur
DB20000I  The SQL command completed successfully.
db2 => call reserve('C100','26.12.2004', 200 , 1 )

  Value of output parameters
  --------------------------
  Parameter Name  : TICKETSCNT
  Parameter Value :  200 

  Return Status =  0 

db2 =>


--------------------------------------------------------------
-- пытаемся блокировать 991 билет во 2 окошке - не получается
-- т.к. 991+200 > 1000
--------------------------------------------------------------
db2 => call reserve('C100','26.12.2004', 991 , 2 )

  Value of output parameters
  --------------------------
  Parameter Name  : TICKETSCNT
  Parameter Value : - 1 

  Return Status =  0 


---------------------------------------
-- десять билетов блокируется запросто
---------------------------------------
db2 => call reserve('C100','26.12.2004', 10 , 2 )

  Value of output parameters
  --------------------------
  Parameter Name  : TICKETSCNT
  Parameter Value :  10 

  Return Status =  0 

db2 =>

таким образом чтобы заблокировать соответствующие билеты с 1000 станций
(начать соответствующие транзакции, каждая из которых может кончится когда угодно, не мешая другим и при этом всё будет согласовано и ни каких лишних билетов на машине с Celeron 1300 в качестве сервера уйдет примерно 4 секунды.
...
Рейтинг: 0 / 0
Задача для версионника
    #32828129
Фотография tygra
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Я уже начинаю думать, что мы со слепым тут разговариваем - не видит человек ничьих постов, кроме своих, ну хоть ты тресни.
Доктор....... Доооооктооооорррррр......................рррррр.....рррр..... :)

авторНапишем хранимую процедуру на С++ в которой создадим именнованный мьютекс. Таким образом получится что инсертить в таблицу LOCKS (вместе со срабатыванием соответствующего триггера BILocks) в один момент времени может только один клиент.
Инсертить всегда в один момент времени может только один клиент, особенно если он использует транзакцию.

gardenman начать соответствующие транзакции , каждая из которых может кончится когда угодно, не мешая другим и при этом всё будет согласовано и ни каких лишних билетов на машине с Celeron 1300 в качестве сервера уйдет примерно 4 секунды
Может вы все же объясните, что вы понимаете под транзакциями в данном контексте???

=============
Сам с собой человек разговаривает - круто, да? А зачем на форус обратился? Чтобы его гениальный алгоритм все увидели? Дык увидели, и даже прокомментировали.... Что же еще?
-- Tygra's --
...
Рейтинг: 0 / 0
Задача для версионника
    #32828492
Фотография Я и ёжик
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
gardenman"Усиленное решение".
Вообще существует ещё много интересных и не менее полезных занятий в этом мире, например изобретение вечного двигателя.


gardenman
Я так понимаю единственная проблема была в триггере BILocks,

Не единственная, а первая попавшаяся на глаза . В Вашу синхронизацию как минимум надо включить оба ваши триггера на sales и и все возможные операции на routes, только тогда можно будет ожидать корректных результатов. Т.е. по сути Вы ВСЕ операции с базой данных над таблицами locks,sales, routes выстраиваете в очередь, т.е сериализуете ( как вам и говорил vc123) только не на уровне БД а на уровне OS, искусственно выделив из сериализации часть транзакции по вводу данных паспортов. Не проще ли выделить этот ввод в отдельную транзакцию и не мучиться изобретением велосипедов?

tygra Я уже начинаю думать, что мы со слепым тут разговариваем - не видит человек ничьих постов, кроме своих, ну хоть ты тресни.
Он же сказал уже: "Смысл того, что здесь написано совсем другой. И я имел в виду совсем не то, о чем ты подумал. Я хочу сказать что существует класс задач, для которых Оракл не катит." Его не интересует как "правильно и эффективно" решить реальную задачу, он хочет показать, что в такой кривой постановке её можно решить только на блокировочнике с грязным чтением.
...
Рейтинг: 0 / 0
Задача для версионника
    #32829376
iLLer
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
В упор не вижу причин для:
1) Невозможности реализации на Oracle или любой другой SQL-СУБД. И даже не столько невозможности, сколько не профильности. Если у Вас будет один сервак и тыща касс, то многие СУБД могут загнуться.
2) Необходимости применения уровней изоляции (не блокировок, так как это понятие растяжимое). Необходимо разделить понятия транзакционности. То ли для Вас транзакция - это факт изменения данных в БД, то ли факт оформления покупки. И совершенно не обязательно одно натягивать на другое.
3) Необходимости применения синхронизации работы клиента (А какого черта Вы тогда вообще в СУБД лезете, еще чуть-чуть подправить, организовать хранилище данных в файле, и будет совсем автономная система, а вернее СУБД). СУБД для того и нужна, чтоб организовать надежный доступ многих страждующих к одним данным и она берет на себя задачу сериализации транзакций.
Пора призывать модераторов закрывать эту тему. Ибо начальный вопрос потерян и не уместен в данном контексте.
...
Рейтинг: 0 / 0
Задача для версионника
    #32829871
gardenman
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Его не интересует как "правильно и эффективно" решить реальную задачу, он хочет показать, что в такой кривой постановке её можно решить только на блокировочнике с грязным чтением.

1) Хотел бы увидеть почему моё решение неправильное. Пожалуйста - аргументы. Хотите сказать что оно не работает? Привидите такую последовательность действий над системой, когда результат будет не таким, каким я его ожидаю.
2) Почему моё решение неэффективное? У вас есть более эффективное? требующее меньшего I/O, меньших затрат на програмимирование, увеличивающее параллелизм?

>Пора призывать модераторов закрывать эту тему
У нас появился цензор? Меня записали в еретики? Сожжете на костре?

3) У каждой задачи существует множество решений, также, как существует множество людей. И увы, не нам решать имеют ли они право на существование.

Теперь еще раз медленне и подробнее.
Два пользователя хотят изменить в записи поле с остатком.
пользователь А делает select for update nowait - блокирует запись.
Пользователь Б также делает select for update nowait - и получает отлуп. Если он сделает просто select for update - то подвиснет до тех пор, пока А не сделает commit.
Таким образом они редактируют запись по очереди . И от этого конечно не избавиться ни в одной системе. Но в отличие от версионника, блокировочник может построить очередь из таких незавершенных запросов (транзакций) и, спрогнозировав сколько билетов осталось в кассе ( несмотря на то, что еще не все транзакции закоммичены ) сказать - можете не занимать очередь, вам все равно не хватит. Но если хотите испытать судьбу - подождите. Может вам и достанется.

Или, например в другом случае, не просто дать отлуп на select for update nowait, а сказать - знаете, а эту запись редактирует сейчас Вася Пупкин, который сидит этажом выше, и хочет списать со счета 50 баксов, на счете останется еще 100 баксов. И, если вы хотите снять в пределах этих ста баксов - то пожалуйста - путь свободен. Если больше - то извините...((

За сим прощаюсь с вами. Всем удачи.
...
Рейтинг: 0 / 0
Задача для версионника
    #32829976
Серега
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
2 gardenman
ИМХО. Все твои ухищрения основаны на желании открыть транзакцию при обращении пасажира и закрыть ее после ввода 600 документов. Я тебе в самом начале описал как можно сделать в системах с высокой конкуренцией за данные. Просто для этого надо продумывать соответствующую структуру данных. Извращаться на хреновой (гипотетически упрощенной и отвлеченной от конкретной задачи) структуре с уровнями изоляции конечно можно, но непродуктивно. Опять же повторюсь - ИМХО .
...
Рейтинг: 0 / 0
Задача для версионника
    #32830119
iLLer
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
to gardenman:
1) Никто не говорит, что Ваше решение неправильное. Вообще в жизни нет такого понятия, как правильно.
2) На счет меньших затрат на программирование - это точно. В Вашем варианте Вы делаете работу (по программированию), которую должна выполнять СУБД.
3) Я не цензор, это мое мнение
4) Все имеют прваво на существование
5) Также медленно: к чему вообще селект? В том смысле зачем Вам селект в одной транзакции с апдейтом?
Первая транзакция: селект состояния по билетам, далее по желанию вывод на экран, сохранение в файл, распечатка, отсылка и т.д.
Вторая: клиент посылает апдейт на изменение значения доступного кол-ва либо добавляет в систему документ о проведении операции резервирования, которая влечет изменения статусов доступности. В зависимости от реализации.
Если вторая транзакция вернулась с ошибкой, то все ясно, мест нет. И можно сразу смело посылать покупателя, т.к. мест нет. Если места есть, то вбиваются детали и переводится состояние из "резерв" в "продан".
Поднимитесь вверх и медленно прочтите мое предложение о реализации системы резервирования. Я уже это писал. И не только я. А с прогнозированием это Вы загнули.
...
Рейтинг: 0 / 0
Задача для версионника
    #32830471
Фотография tygra
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Да не слышит человек ни одного другого, отличного от его самого, мнения и решения. Придумал кошмар ночной и радуется до смерти. До смерти - это потому, что помрут все с такой реализацией.

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

Ээээхххххххх

-- Tygra's --
...
Рейтинг: 0 / 0
Задача для версионника
    #32833384
gardenman
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Хорошие вы все ребята, душевные....
Я сначала было подумал не отвечать... но блин вчера было так скучно и тоскливо в форуме... А вообще чем попусту сотрясать воздух (а ля тигра) я предпочитаю сначала подумать, а потом дать аргументированный ответ.

Для начала несколько ситуаций:
1) Студент вытаскивает на экзамене говорит препаду: 13 билет, но отвечать я буду на 1 билет, потому, что я только его выучил
2) Заказчик приходит к подрядчику и говорит: вот нужно написать такую-то систему, можете ее реализовать на Оракле. Подрядчик - конечно можем...так что тут у Вас? а.. отлично, мы беремся, вот только реализация будет на MSSQL и вот это и это вы как-нить сами...
3) Если кто-то расписался в своем бессилии доказать теорему Ферма, то не проще было бы поменять вообще эту теорему, так сказать изменить условия задачи?

Ситуация из жизни, с которой я сталкиваюсь ежедневно на работе: представляете (сразу говорю, автор не я!!!!) у нас параметры в ХП передаются через запись в постоянной таблице!!!
А что это значит? То, что если человеку взбредёт в голову войти под своим своим логином с двух компов, то получится конфликт параметров!

Рассмотрим подробнее ситуацию с резервированием. Сия ситуация означает, что транзакций в системе будет несколько. Одна с резервированием, другая - собственно с продажей. Следовательно записи на резервирование нужно как-то идентифицировать. Варианты: по имени пользователя, по номеру сессии, по коду терминала.
1)По имени пользователя: если это так, то с двух терминалов под одним и тем же именем не зайти - конфликт параметров ХП (смотрите ситуацию, описанную абзацем)
2)По номеру сессии: в случае глюка/отсоединения терминала мы теряем номер сессии, придется каким-то образом оперативно чистить зарезервированные билеты.(у Оракла ведь есть триггер на закрытие соединения? в любом случае у MS такого точно нет). А как тогда быть с внесенными вами данными по 599 паспортам? *я читаю внимательно все что вы пишете, и ищу контраргументы*.
3)По коду терминала: та же самая ситуация что и по номеру сессии.

Знаете, ну как-то влом писать сборщик мусора, который в тоже время должен отрабатывать достаточно оперативно. Намного более дешевое (с точки зрения I/O) и простое решение - просто откатить транзакцию.

Вы думаете задача представленная здесь - единственная в своем варианте?

Есть еще одна задачка над которой все думают и все решают по-совему. Нужно зачислить на счета зарплату 100000 человек. Предположим в компе уже имеется этот список в какой-то таблице. Хотите пообсуждать как будет выглядеть такое решение? С учетом, что в системе работает сразу несколько сотен юзеров? Как сделать так, чтобы все отработало в приемлемые сроки с минимумом накладных расходов? Или, например, как сделать так чтобы эта операция была распараллелена между несколькими процессами и количество конфликтов было бы минимальным?

Ситуация из жизни (у меня на работе, делал не я ). Идет прием бланков строгой отчетности (БСО). Имеется документ на 20000 бланков. У каждого бланка свой индивидуальный номер. Бланки должны быть приняты одновременно (документ-то один! сервер Sybase ASE). Рузультат: После небольшого скандала документ решили разбить на 4 по 5000. Понятное дело - просто криво спроектированна реализация. А как бы вы решали эту задачу?
...
Рейтинг: 0 / 0
Задача для версионника
    #32833392
gardenman
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Задачка специально для tygra, как для любителя MSSQL:
Предположим, у нас имеется некий набор договоров. Над определенной группой договоров мы должны провести некую группу однотипных операций, например - банальное расторжение. Задача - Оператор в гриде на своем рабочем месте помечает эти договора (например заносит их id во временную таблицу) а затем передает этот список в ХП, которая все их закрывает. Затем дополняет список этих договоров еще некоторым количеством договоров (отбирая их по какому-нибудь критерию), а затем - передает их другой ХП, которая их переоформляет на новых условиях. Затем чистит пометки и повторяет операцию снова. Как это будет выглядеть на MSSQL? Понятное дело что временная таблица должна быть создана не в какой либо ХП, а самим приложением. И это должна быть не таблица с ##, потому как в этом случае она будет доступна всем сесииям. А тепрь еще наложим условие, что приложение у нас написано,исходников нет, и код мы можем только на сервере.
...
Рейтинг: 0 / 0
25 сообщений из 123, страница 2 из 5
Форумы / Проектирование БД [игнор отключен] [закрыт для гостей] / Задача для версионника
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]