BEST logo логотип компании БЭСТ - программы для бизнеса ПРОДАЖИ
+7 (991) 312-04-37
trade@bestnet.ru
ПОДДЕРЖКА
+7 (495) 775-66-76
consult@bestnet.ru
СКАЧАТЬ
Обновления
Дистрибутивы
Авторизация

Логин:
Пароль:
Забыли свой пароль?
Регистрация
ВАШ ВОПРОС

Доступ к Личному кабинету закрыт!
Как получить доступ?


Главная  / Поддержка  / Форум  / Публичные форумы  / Программирование приложений  / Вопрос по блокировке записей.

Форум

Поиск  Пользователи  Правила 
Закрыть
Логин:
Пароль:
Забыли свой пароль?
Регистрация
Войти
 
Страницы: Пред. 1 2 3
RSS
Вопрос по блокировке записей.
 
При такой конструкции в сети на 10 пользователей Вы точно совершенно две одинаковые записи не получите.
Мы говорим о механизме записи: я не проверял точность индексного ключа и т.п.
 
Цитата
nordk пишет:
При такой конструкции в сети на 10 пользователей Вы точно совершенно две одинаковые записи не получите.
Мы говорим о механизме записи: я не проверял точность индексного ключа и т.п.

Ну, чтож, давайте проверим. (Хотя при чем тут индекс).

Для этого возьмем функцию, создающую Н\Н с заполнением нескольких полей. Ту, которую рассмотрели ранее:
Код
STATIC PROCEDURE CreateNewProduct()
Local sNewNNumReal:=Space(13)
 SET ORDER TO TAG TAG_NNum
 DbGoBottom()
 sNewNNumReal:=mlabel->nnum
 if(sNewNNumReal==AllTrim(sNewNNumReal))
 if(.NOT.(IfAllChar(sNewNNumReal)))
 WHILE Mlabel->(DBSEEK(UPPER(" "+sNewNNumReal)))
sNewNNumReal:=InCreaseOne(MLABEL->NNUM)
 ENDDO 
 Mlabel->(ADDREC())
 Mlabel->NNUM:=sNewNNumReal
 Mlabel->GRUP:="00001"
 Mlabel->NAME:="Новая"
 Mlabel->FULLNAME:="Новая полное"
 Mlabel->ORD_POLICY:=1
 Mlabel->ID_LABEL:=StepPlus()
 Mlabel->mdim:="0000000000000000001040"
 Mlabel->( F_DBUNLOCK() )
 endif 
 endif
return

Функции, которая использует ф-я создани ном-ры приведу ниже.

Теперь, используем эту функции в нашей спецфункции:
Код
StartTest()
STATIC PROCEDURE StartTest()
Local Temp_I:=0
Local dStart,dEnd
dBpUSH()
dStart:=Time()
If (DbF()=="MLABEL")
    For Temp_i:=1 to 20000
      CreateNewProduct()
    NEXT
ENDIF
dEnd:=TIME()
SayAndWait("Время старта "+Var2Char(dStart)+" время окончания"+Var2Char(dEnd))
DbPop()
RETURN


Будет выводиться время начала и время окончания работы спецф-ии.
Подготовим справ номенклатуры. Для этого удалим там все записи, создадим запись под номером "0000000000001"(Этого изначально требует работа со справочником) в группе "00001". У нас запущено одно окно.
1. Запускаем спецфункцию. (Создадим 20к записей для "веса").
2. Запускаем 2е окно и как можно быстрее запускаем в обоих окнах спецфункцию.
Результат записываем. Вот что получилось у меня(МИН:СЕК):
1.10:50 - 11:08. Dbf Viewer показывает 20001 запись. Н\Н Последней 20001.
2. 1е окно: 13:23 - 13:59
2е окно: 13:24 - 14:00
Результат: Dbf Viewer показывает 60001 запись. Н\Н Последней 42276.

Проведем 2й раз опыт (подгтовка справочника, реиндексация).
1.33:07 - 33:21. Dbf Viewer показывает 20001 запись. Н\Н Последней 20001.
2. 1е окно: 34:20 - 34:57
2е окно: 34:21 - 34:58
Результат: Dbf Viewer показывает 60001 запись. Н\Н Последней 42103.
Результат, в общем-то плачевный. Получилось, что около 18000 записей дублируют номера. (Хотя один раз получился результат с дубляжом порядка 500 записей, там был немного др алгоритм, но принцип проверки тот же.).
Теперь рассмотрим причину, по которой такое происходит. Обратимся к куску кода:
Цитата

WHILE Mlabel->(DBSEEK(UPPER(" "+sNewNNumReal)))
sNewNNumReal:=InCreaseOne(MLABEL->NNUM)

ENDDO
Mlabel->(ADDREC())
Mlabel->NNUM:=sNewNNumReal
Mlabel->GRUP:="00001"
Mlabel->NAME:="Новая"
Mlabel->FULLNAME:="Новая полное"
Mlabel->ORD_POLICY:=1
Mlabel->ID_LABEL:=StepPlus()
Mlabel->mdim:="0000000000000000001040"
Mlabel->( F_DBUNLOCK() )

Жирным выделением отметил место где начинается "критический" код и где он заканчивается. Если разделить эти участки кода от одновременного исполнения - то никаких ошибок не будет. Как это сделать сейчас?
Естественно "заморозить" процесс я не могу. Однако, можно поступить по-идиотски, а именно разделить его так:
Цитата

Do While (.NOT.(lUnique).AND.(nJ<1000))
TRY
USE (sPath) NEW Alias TEmp
lUnique:=.T.
SELECT ("MLABEL")
SET ORDER TO TAG TAG_NNum
CATCH oErr
nJ+=1
end
enddo
//правильнее еще сделать проверку на велич счетчика.
WHILE Mlabel->(DBSEEK(UPPER(" "+sNewNNumReal)))
sNewNNumReal:=InCreaseOne(MLABEL->NNUM)

ENDDO
Mlabel->(ADDREC())
Mlabel->NNUM:=sNewNNumReal
Mlabel->GRUP:="00001"
Mlabel->NAME:="Новая"
Mlabel->FULLNAME:="Новая полное"
Mlabel->ORD_POLICY:=1
Mlabel->ID_LABEL:=StepPlus()
Mlabel->mdim:="0000000000000000001040"
Mlabel->( F_DBUNLOCK() )
Close Temp

Имея такой инструмент, можно было бы вообще отказаться от проверки и переделать алгоритм, но посмотрим что получиться при таком коде.
Результаты:
1. 14:21 - 14:39. Записей 20001, Н\Н последней 20001. Все верно.
2. 1е окно 15:28 - 16:27
2е окно 15:29 - 16:28
Результат: Записей - 60001, номер последней записи 60001. А это значит, что не допущено ни единой ошибки!!!!

Код
Function IncreaseOne(cString)
Local nLength:=0
Local cIncreased:=""
Local nPosition:=0 //Цифра - разряд
nLength:=len(cString)
cIncreased:=stuff(cString,1,nLength-1,"")
If(IsDigit(cIncreased))
nPosition:=Val(cIncreased)
if(nPosition==9)
 if(nLength==1)
cIncreased:=""// нужен сЛУЧАЙНЫЙ СИМВОЛ
 else
nPosition:=0
cIncreased:=IncreaseOne(stuff(cString,nLength,nLength,""))
if(.NOT.(cIncreased==""))
cString:=cIncreased+Var2Char(nPosition)
else
cString:=""
endif
 endif
else
nPosition+=1
cString:=stuff(cString,nLength,nLength,Var2Char(nPosition))
endif
else
nPosition:=0
cIncreased:=IncreaseOne(stuff(cString,nLength,nLength,""))
if(.NOT.(cIncreased==""))
cString:=cIncreased+Var2Char(nPosition)
else
cString:=""
endif
endif
return cString

Function IfAllChar(cString)
Local bIfNotNumExist:=.T.
Local nLen:=len(cString),temp_i:=0,temp_j:=0
if (nLen!=0)
While(bIfNotNumExist)
 if(IsDigit(cString))
bIfNotNumExist:=.F.
 else
cString:=Stuff(cString,1,1,"")
 endif
enddo
endif
return bIfNotNumExist
//Измененная ф-я создания:
STATIC PROCEDURE CreateNewProduct()
Local sNewNNumReal:=Space(13)
Local lUnique:=.F.
Local nJ:=1,oErr
Local sPath:=LoadPath()+"TEST\BOM_def"
 SET ORDER TO TAG TAG_NNum
 DbGoBottom()
 sNewNNumReal:=mlabel->nnum
 if(sNewNNumReal==AllTrim(sNewNNumReal))
 if(.NOT.(IfAllChar(sNewNNumReal)))
Do While (.NOT.(lUnique).AND.(nJ<1000))
 TRY
USE (sPath) NEW Alias TEmp
lUnique:=.T.
SELECT ("MLABEL")
SET ORDER TO TAG TAG_NNum
 CATCH oErr
nJ+=1
 end
enddo
 WHILE Mlabel->(DBSEEK(UPPER(" "+sNewNNumReal)))
sNewNNumReal:=InCreaseOne(MLABEL->NNUM)
 ENDDO 
 Mlabel->(ADDREC())
 Mlabel->NNUM:=sNewNNumReal
 Mlabel->GRUP:="00001"
 Mlabel->NAME:="Новая"
 Mlabel->FULLNAME:="Новая полное"
 Mlabel->ORD_POLICY:=1
 Mlabel->ID_LABEL:=StepPlus()
 Mlabel->mdim:="0000000000000000001040"
 Mlabel->( F_DBUNLOCK() )
 Close Temp
 endif 
 endif
return
//В качестве "Блокирующего" файла 
//взял BOM_def, он у нас все 
//равно пуст. Файл обязательно
// должен присутствовать в папке TEST!!!!!!
Изменено: Саак Шахламджян - 26.08.2008 15:07:44
 
А теперь первый вариант предложите сделать
одновременно 10 операторам и получить ошибку
 
Цитата
nordk пишет:
А теперь первый вариант предложите сделать
одновременно 10 операторам и получить ошибку

Первый вариант "делали" 2 оператора.
Если Вы имели ввиду создание одной единицы, то да-добиться такого результата весьма сложно, т.к. это программа исполняется быстро. Но суть не в этом, меня даже не это интересует. Интересует правильное написание программы.
Конечно, я мог бы спорить дальше и для Вас рассчитать вероятность такого "плохого" исхода для 10ти операторов, взяв реальное время исполнение+создание трех единиц (у нас именно так), но смысла в этом, думается нет.
 
Да я думаю Ваши теоретические изыскания смысла не имели уже с того момента что ввод такой записи как новый номенклатурный номер делает как правило строго определенный человек во избежание таких факторов как двойные номенклатуры (с разными наименованиями) и даже для того чтобы просто дать наименование надо подумать как следует и ни о каком вводе 60000 номенклатур в минуту и даже 2 в секунду речи на практике быть не может и сильно врядли это стоит позволять делать разным людям в принципе, с позиций организации труда :funny:
А уж тем более говорить что Ваш пример делало 2 человека даже не пытайтесь - делали 2 цикла, потому как для человека ввод 2000 номенклатур (правильных номенклатур это норма на целый день - а в Вашем примере 60000 за несколько минут !!! И именно в этом ошибка Вашей оценки).А Вы еще к каждой номенклатуре хотите и спецификацию и увязку между материалами и товарами. И вот именно на этом основании я говорю Вам о низкой практической интенсивности ввода данных и бессмысленности дуть на воду. А с позиций теории я Вашу
точку зрения не оспаривал...только так при работе с БД подходят как Сан Саныч написал в ситуациях когда действительно интенсивность высокая... А здесь Вы наворотили столько проверок вместо простого кода... (ИМХО)
 
Цитата
nordk пишет:
А здесь Вы наворотили столько проверок вместо простого кода... (ИМХО)

Интересно о какой проверке идет речь? (Или имелось ввиду разделение куска кода во времени?) Я такой ерунды, разумеется, не писал в программе и писать не собираюсь. "Ежу" понятно почему так делать нельзя.
Было желание сделать правильно, и самое главное научиться это делать, только и всего.
 
Если Вам нравится делать так - делайте так.
Понятие "правильно" весьма субъективно.
Свою точку зрения навязывать не буду.
Моя задача консультировать о возможностях...
 
Цитата
nordk пишет:
Если Вам нравится делать так - делайте так.
Понятие "правильно" весьма субъективно.
Свою точку зрения навязывать не буду.
Моя задача консультировать о возможностях...

Второй вариант - неправильно!!! Во втором варианте должно быть Входвсемафор()
Выход(). Этого там нет. То, что я привел вместо этого - даже не знаю как назвать...
На крайний случай (я в WinApi не так уж и силен), создать объ-ект событие, общий по сети для всех (это м\б файл), и сделать у него метод, вроде WaitForSingleObject, который и будет пытаться открыть такой файл, а если он занят, то замораживать процесс, ожидая освобождения (насколько я знаю в Windows такие объекты заранее определены, не знаю, возможно ли такой построить самому). Если бы так можно было сделать, останется Вопрос о синхронизации данного действия.
Страницы: Пред. 1 2 3
Читают тему (гостей: 2)