powered by simpleCommunicator - 2.0.60     © 2026 Programmizd 02
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Форумы / FoxPro, Visual FoxPro [игнор отключен] [закрыт для гостей] / Вставка в таблицу записи с уникальным id
21 сообщений из 46, страница 2 из 2
Вставка в таблицу записи с уникальным id
    #32369024
Фотография sparrow
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Модератор форума
А никто не пробовал написать простой COM сервер? И только у него получать всякие иды, мне кажется это самое надежное решение.
...
Рейтинг: 0 / 0
Вставка в таблицу записи с уникальным id
    #32370148
Фотография FM32YO aka KID
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
вернулся снова к собственному коду - свое самое родное...
принимаю во внимание Ваши замечания по поводу того, что при работе нескольких юзеров возможно дублирование уникального номера..
ВОПРОС!!!
А если я буду делать вставку новой записи так:
Begin Transaction
INSERT INTO......
END TRANSACTION

по идее, пока один юзер делает добавление записи - другой не сможет...
Может кто поделится соображениями ?
И, какое сообщение по идее должен получить 2-й юзер, если 1-й еще не завершил транзакцию?
Если сообщение системное - как его заменить на свое - Русское?
...
Рейтинг: 0 / 0
Вставка в таблицу записи с уникальным id
    #32370172
bdv9
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Думаю транзакция здесь не поможет.
Насколько я знаю транзакция действует только для данного пользователя, а другой может делать что угодно.
Советую все-таки перейти на создание уникального идентификатора для таблицы, используя дополнительный файл - это проверенная технология: работает давно и без сбоев.
...
Рейтинг: 0 / 0
Вставка в таблицу записи с уникальным id
    #32370217
Фотография FM32YO aka KID
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Да мой метод и использует дополнительный файл-таблица с полями
Next_id N(10), TableName C(10)
то есть для каждой таблицы в БД есть строка в этой дополнительной таблице, и данные оттуда берутся

FUNCTION NewId
PARAMETERS cTableName
select ids.next_id AS Next_n FROM ids ;
WHERE ALLTRIM(UPPER(ids.table_name)) = ALLTRIM(UPPER(cTablename));
INTO CURSOR nexter
nNewId = nexter.Next_n + 1
UPDATE ids SET next_id = nNewId WHERE ALLTRIM(UPPER(ids.table_name)) = ALLTRIM(UPPER(cTablename))
RETURN nNewId
*ENDFUNC

Но Гуру данного вфорума указали на возможность 2-х юзеров ОДНОВРЕМЕННО вызвать ХП NewId....
Или Ва имели в виду нечто иное?
Дайте пример работающего кода если можно, а то все, что тут перечислялось так или иначе НЕ всегда работает...
...
Рейтинг: 0 / 0
Вставка в таблицу записи с уникальным id
    #32370245
bdv9
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Собственно пример рабочего кода я уже приводил в этом топике.
И у меня он работает везде, давно и без сбоев.
В некоторых проектах (правда в тестовых) применял его в связке ХП+Default value.
...
Рейтинг: 0 / 0
Вставка в таблицу записи с уникальным id
    #32371097
Фотография FM32YO aka KID
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
попробовал так:
Форма1 и форма2
абсолютно одинаковые только в форма1 на СОХРАНИТЬ
Begin Trans
Insert...
.
.
Wait window "1111"
END Trans
thisform.release()
В Форма2 на сохранить
Begin Trans
Insert...
.
.

END Trans
в итоге обе формs висят на єкране и "ждут " пока с 1-й не погашу Wait window
Иными словами утверждение о том, что каждая транзакция касается только того пользователя, который ее начал - неверно...
вот только посоветуйте КАК сделать при этом в форме2 системное сообщение "Подождите... ля ля ля..."
...
Рейтинг: 0 / 0
Вставка в таблицу записи с уникальным id
    #32371158
bdv9
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Сегодня проверил.
Действительно ты прав.
Может можно и так.

<вот только посоветуйте КАК сделать при этом в форме2 системное сообщение "Подождите... ля ля ля..."
Не знаю, но попробуй пойти не через транзакции, а через RLOCK()

Код: 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.
set repr to  5 

sele table
go <record>

i =  0 
lnKol =  100    && Кол-во попыток можно задать
llOk = .F.
do while Not llOk And lnKol >  0 
if not rlock()
i = i +  1 
lnKol = lnKol -  1 
wait wind nowa [Подождите файл временно заблокирован. Попытка№ ] + AllTrim(Str(i))
else
llOk = .T.
<Твои действия>
unlock
endif
enddo

If Not llOk
   Wait Wind NoWa [Сообщение о неудачной попытке]
Else
   <Твои действия>
EndIf
...
Рейтинг: 0 / 0
Вставка в таблицу записи с уникальным id
    #32371201
Фотография FM32YO aka KID
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
огромное спасибо!
Дома опробую...
хотя... заранее знаю, что проджект мой будет юзать только 1 юзер....
просто на будущее интересуюсь....
...
Рейтинг: 0 / 0
Вставка в таблицу записи с уникальным id
    #32371266
bdv9
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Это правильно.
Понравилась фраза с foxclub: "Стели солому направо и налево" .
...
Рейтинг: 0 / 0
Вставка в таблицу записи с уникальным id
    #32371340
Фотография FM32YO aka KID
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
LOCAL t1, t2, t3, t4, Co1, Co2

t1 = ALLTRIM(UPPER(thisform.t1.value))
t2 = ALLTRIM(UPPER(thisform.t2.value))
t3 = thisform.t3.value
t4 = thisform.t4.value
Co1 = thisform.Co1.value
Co2 = thisform.Co2.value

private lError
lError = .f.
SET REPROCESS TO automatic &&20

begin transaction
on error lError = .T.

INSERT INTO Tovar (name, code, price, idgroup, idunits, Quantity, del_no) ;
VALUES (t1, t2, t3, Groups_q.id, Units_q.id, t4, 1)

wait window " 1111 "

on error
if lError
ROLLBACK
=messagebox("Повторите еще раз")
else

END TRANSACTION
endif
thisform.release()
*******************************
такой Вариант порекомендовал Сергей Титов...
все четко работает НО
если 1-й юзер "держит" транзакцию...
посредством wait window " 1111 " в моем примере...
(сам понимаешь в реальной задаче wait window " 1111 "
не будет присутствовать.. я его добавил исключительно в целях
эксперимента... как же мне иначе симулировать "занятость" записи..
если я тест провожу один..)
2-й юзер при таком раскладе - SET REPROCESS TO automatic
получает "видимость" того, что форма попросту "зависла"
лично я никак на глаз не мог определить... то ли винда висит.. то ли
прога...
ну иллюзия зависания полная.... вот интересно КАК бы это обойти????
Если поставить SET REPROCESS TO 1
то есть одна и только одна попытка
то 2-й юзер естественно сразу получит в лоб сообщением
"Повторите еще раз" и форма закроется....

Дело в том, что в теперешней моей задаче форма ввода данных содержит
примерно 30 контроллов... естественно юзер, заполнив их будет очень
"рад" потерять все набранное из-за того, что другой юзер в это время
что-то добавляет я базу...

разве что НЕ закрівать форму в случае неудачного доступа к залоченной таблице...
...
Рейтинг: 0 / 0
Вставка в таблицу записи с уникальным id
    #32374978
Фотография ВладимирМ
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Очень кратко, пока не началось... :)

Ошибка №130 (также, как и 108 и 109) связана с конфликтом совместного доступа. Наиболее вероятная причина - это некорректное использование PrivateDataSession.

Помню, когда-то давно у меня такие ошибки были. Но как не пытался, но добиться того же эффекта с моим NewID() у меня не получилось.

Транзакция.

Необходимо стремиться к тому, чтобы время открытой транзакции было сведено к минимуму. Дело в том, что открытая транзакция блокирует все области, которые были изменены пользователем до завершения транзакции. А это много чего. Так сразу все и не перечислешь. Например, может быть заблокирован ВЕСЬ структурный индексный файл.

Общая логика модификации и записи данных примерно следующая:

-) Накладывается буферизация на таблицы источники
-) Выполняется модификация в буферах
-) А вот сам процесс сброса данных из буфера в исходные таблицы обрамляется транзакцией.

При такое идеологии в случае отката транзакции (по разным причинам) система возвращается в то состояние, в котором она была до момента открытия транзакции. Т.е. к моменту уже заполненного, но еще не сброшенного буфера. Соответсвенно пользователь может повторить попытку сброса буфера без повторного ввода данных.

Ну что-то вроде:

=CURSORSETPROP('buffering',3,'MyTable')
INSERT INTO MyTable (Field1) VALUES (1)

BEGIN TRANSACTION
IF TableUpdate(.T.,.T.,'MyTable')
END TRANSACTION
ThisForm.Release()
ELSE
ROOLBACK
MessageBox('Сохранить не удалось. Повторите попытку')
ENDIF
...
Рейтинг: 0 / 0
Вставка в таблицу записи с уникальным id
    #32392948
This is the function I use to generate the Integer type Primary Keys for my tables.Requires a NextKey.dbf table. Enjoy:

Код: 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.
LPARAMETERS tcTable
** tcTable - Name of the table where a new record is added

LOCAL lnCurrSelect, ;
   lcTableName, ;
   llUsed, ;
   lnCurrReprocess, ;
   luKey, ;
   lcKey, ;
   lcField, ;
   lcOldTalk, ;
   liOldidKey, ;
   lnDay, ;
   lnHour

lcOldTalk=SYS( 103 )
SET TALK OFF

lcAsserts=SET( "ASSERTS" )

SET ASSERTS ON

ASSERT TYPE( "tcTable" ) =  "C"  ;
   AND ! EMPTY(tcTable) MESSAGE PROGRAM()+ ": Parameter must be character type and not empty..." 

* Save the current work area, open the NEXTID table
* (if necessary), and find the row with the desired table name. If it
* doesn't exist, create a record for it.

lnCurrSelect = SELECT()
llUsed       = USED('NextKey')
lcTableName  = UPPER(ALLTRIM(tcTable))
IF llUsed
   SELECT "NextKey"
   SET ORDER TO "cTableName"
ELSE
   SELECT 0
   USE NextKey ORDER cTableName AGAIN SHARED
ENDIF llUsed
SEEK lcTableName
IF NOT FOUND()
   LOCATE
   CALCULATE MAX(NextKey.iidkey) TO liOldidKey
   INSERT INTO NextKey (iidkey, iNextKey, cTableName, iIncrement) ;
      VALUES (liOldidKey+1, 0,lcTableName, 1)

ENDIF NOT FOUND()

* Increment the next available ID.

lnCurrReprocess = SET('REPROCESS')
SET REPROCESS TO AUTOMATIC

IF RLOCK()
 
   REPLACE iNextKey WITH iNextKey + iIncrement
 		   
   luKey = iNextKey
   UNLOCK
ENDIF RLOCK()


* Cleanup and return.

SET REPROCESS TO lnCurrReprocess
IF NOT llUsed
   USE
ENDIF NOT llUsed

SELECT (lnCurrSelect)
SET TALK &lcOldTalk
SET ASSERTS &lcAsserts

RETURN luKey
...
Рейтинг: 0 / 0
Вставка в таблицу записи с уникальным id
    #32393296
Por
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Por
Гость
2 sparrow

Я делал COM для раздачи "инвентарных" номеров (реестровых). Но там проблема несколько отличалась. Дело в том, что требуемый номер должен был быть уникальным в пределах базы данных, а не только одной таблицы, как в случае с PK.
...
Рейтинг: 0 / 0
Вставка в таблицу записи с уникальным id
    #32393846
Фотография ВладимирМ
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Rosty Vygovsky, Lynbrook, NY
Видимо Вам тяжело читать по русски, но Ваш код повторяет целый ряд типичных ошибок. Он, конечно, работоспособный, но при очень определенных условиях.

Посмотрите мой код страницей раньше. Там в комментариях я написал почему и зачем делал кое-какие дополнительные команды, которых нет в Вашем коде.
...
Рейтинг: 0 / 0
Вставка в таблицу записи с уникальным id
    #32395659
dasistgut
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Господа, объясните мне, как работает foxpro в случае, когда индексы беруться из специальной таблицы, как предлагает, например, Igor Korolyov.
Насколько я понимаю, алгоритм следующий:
1. Сеанс пользователя НЕ в режиме транзакции.
2. Сеанс выполняет оператор Insert Into...
3. СУБД открывает транзакцию.
4. Срабатывает триггер Insert Row, который берёт из специальной таблицы значение ключа. Значение ключа в специальной таблице увеличивается на 1.
5. Полученное значение ключа записывается туда, куда надо.
6. Транзакция закрывается.

Далее:
Если в этот же момент другой пользователь выполняет те же действия с небольшим запозданием, т.е. если его п.4 приходится на п.5 первого пользователя, он получит то же значение ключа, что и первый. В результате возникнет та же коллизия дублирования ключей.
Или foxpro работает как-то по-другому?
Спасибо.
...
Рейтинг: 0 / 0
Вставка в таблицу записи с уникальным id
    #32395832
andrew_Pr
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
to dasistgut
п.4 второго юзера никогда не пересечется с п.5 первого,
потому что, когда второй юзер дойдет до п.3, его программа
"зависнет" и будет ждать, пока первый юзер не закончит п.6
Или в других БД транзакции работают как-то по-другому? ;)
...
Рейтинг: 0 / 0
Вставка в таблицу записи с уникальным id
    #32395843
Фотография ВладимирМ
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
dasistgut
Все несколько не так. Значение ключа генерится не триггером, а несколько раньше, при генерации Default значения поля. Хотя для разбора полетов это не столь принципаильно.

Дело в том, что открытая транзакция запрещает снимать блокировки установленные любым способом до завершения транзакции.

Применительно к генерации ключа - это означает, что как только в служебной таблице была дана команда LOCK(), то даже последующий UNLOCK не снимет блокировку до закрытия транзакции.

Т.е. другой пользователь не сможет сгенерить ключ, пока первый не разберется с транзакцией.
...
Рейтинг: 0 / 0
Вставка в таблицу записи с уникальным id
    #32396010
dasistgut
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
andrew_Pr
Похоже, что в других БД транзакции действительно работают по-другому.
Делаем простой проект: Delphi+IB. На любую таблицу вешаем примерно такой триггер:
CREATE TRIGGER SET_EMP_NO FOR EMPLOYEE
ACTIVE BEFORE INSERT POSITION 0
AS
declare variable i integer;
BEGIN
i = 1;
if (new.first_name = '1') then
While (i>0) do begin
i = i + 1;
end
END
т.е. если поле first_name инициировано значением '1', то триггер зациклится.
В программе одна форма, на которой DBGrid, с этой таблицей.
Запускаем две копии программы. В первой вставляем запись с first_name = '1' и делаем Post. Прога "виснет", как и следовало ожидать.
Во второй копии вставляем запись с first_name <> '1'. Запись вставляется и эта (вторая) прога продолжает работать нормально.
Т.е. возвращаясь к моему вопросу, юзер на п.3 (по крайней мере в IB, Oracle) не зависнет. Но учитывая объяснение Владимира М становится всё понятно.
Спасибо.
...
Рейтинг: 0 / 0
Вставка в таблицу записи с уникальным id
    #32506998
lesha_spb
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Очень полезный топик, хотя и несколько разросшийся:)
Но по моему надо упоминуть и про такую вещь, как проверка неиспользованных ключей. вот что я имею ввиду: У меня, как и у большинства(я думаю), есть таблица с номером(integer) последнего ключа, так вот рано или поздно его значение станет огромным и при этом многие из уже использованных ключей освободились(например соответсвующая запись удалена). Тогда можно спокойно, например один раз в несколько месяцев, запускать процедуру проверки ключей, которая будет все положительные целые числа меньшие значения в таблице загонять во временную таблицу. Т.о. получаем дополнительные ключи, дальше можно например брать ключи из этой временной таблицы пока она не пустая. Если я в чем не прав поправьте меня.
...
Рейтинг: 0 / 0
Вставка в таблицу записи с уникальным id
    #32507005
lesha_spb
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
>Тогда можно спокойно, например один раз в несколько месяцев, запускать >процедуру проверки ключей, которая будет все положительные целые числа >меньшие значения в таблице загонять во временную таблицу.
Естественно имелись ввиду те значения которые ни где не используются.
Это будет долгая процедура, не спорю.
...
Рейтинг: 0 / 0
Вставка в таблицу записи с уникальным id
    #32507154
Фотография ВладимирМ
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Что значит "станет огромным"?

Предельно допустимое количество записей в DBF-таблице - это 1 billion (единица и девять нулей)

В типе Integer как правило используются только положительные значения, т.е. используется диапазон от 0 до 2,147,483,647

Значит, не боясь переполнения, можно совершенно спокойно удалить 2,147,483,647 - 1,000,000,000 = 1,147,483,647 записей

Если каждый день без перерывов на выходные и праздники удалять по 10,000 записей, то для переполнения нам понадобиться:

1,147,483,647/(365*10,000) = 314 лет

Ваша программа столько проживет?

Так что, не обращайте внимание на "дыры" в нумерации. Не стоящее это занятие.
...
Рейтинг: 0 / 0
21 сообщений из 46, страница 2 из 2
Форумы / FoxPro, Visual FoxPro [игнор отключен] [закрыт для гостей] / Вставка в таблицу записи с уникальным id
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


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