Форум: "Базы";
Текущий архив: 2003.09.08;
Скачать: [xml.tar.bz2];
ВнизСтранное при обновлении одной записи двумя пользователями Найти похожие ветки
← →
AkaSaint (2003-08-11 23:26) [0]Сабж в 3-звенном приложении.СУБД MS Jet 4.0, ADO, 2 клиента
непрерывно обновляют записи в таблице из 200 записей. В двух
словах: после обновления записи одним клиентом второй пытается ее
также обновить и получает ошибку (у провайдера стоит
UpdateMode = upWhereChanged, ResolveToDataSet = False.) Второй
клиент обновляет конфликтующую запись с сервера приложений и снова пытается применить свои изменения. И снова получает ошибку, хотя первый клиент эту запись больше не изменял. В OnUpdateError
провайдера видно, что запись не изменяли: текущие значения записи - все пустые. Почему это происходит? Если вам не лень, взгляните на фрагмент протокола происходящего, который пишет сервер приложений.
vasya_p и zebra - имена клиентов.
17:10:01 zebra BeginTrans
17:10:01 zebra Record with OrderNum=82807 is going to be updated
17:10:01 zebra has added updated record with key 82807
17:10:01 zebra Values:
17:10:01 zebra OrderNum= ClientNum= Country=Зимбабве
VisitDate=13.08.2003 Days=8 Nights=7
17:10:01 zebra CommitTrans
17:10:01 vasya_p BeginTrans
17:10:01 vasya_p Record with OrderNum=82807 is going to be updated
17:10:01 vasya_p Ошибка при обновлении atOrders: Изменение: Record not found or changed by another user (код 1)
17:10:01 vasya_p Original (old) record values:
17:10:01 vasya_p OrderNum=82807 ClientNum=462 Country=Юпитер
VisitDate=03.01.2010 Days=10 Nights=103
17:10:01 vasya_p Current values:
17:10:01 vasya_p OrderNum= ClientNum= Country=Зимбабве
VisitDate=13.08.2003 Days=8 Nights=7
17:10:01 vasya_p New values:
17:10:01 vasya_p OrderNum= ClientNum= Country= VisitDate= Days=30
Nights=
<...>//Запрос на освежение изменившихся записей
17:10:01 vasya_p Открыт ADODataSet. Число записей: 11
17:10:01 vasya_p Values:
<...>
17:10:01 vasya_p 9 OrderNum=82807 ClientNum=462 Country=Зимбабве
VisitDate=13.08.2003 Days=8 Nights=7
<...>
17:10:01 vasya_p Клиент (Orders) обновился
17:10:01 vasya_p RollbackTrans
<...>//zebra изменяет другие записи - не 82807
17:10:01 vasya_p BeginTrans
17:10:01 vasya_p Record with OrderNum=82807 is going to be updated
17:10:01 vasya_p Ошибка при обновлении atOrders: Изменение: Record not found or changed by another user (код 1)
17:10:01 vasya_p Original (old) record values:
17:10:01 vasya_p OrderNum=82807 ClientNum=462 Country=Зимбабве
VisitDate=13.08.2003 Days=8 Nights=7
17:10:01 vasya_p Current values:
17:10:01 vasya_p OrderNum= ClientNum= Country= VisitDate= Days=
Nights=
17:10:01 vasya_p New values:
17:10:01 vasya_p OrderNum= ClientNum= Country=Юпитер
VisitDate=03.01.2010 Days=30 Nights=103
Если вы дочитали до этого места - мои вам горячие поздравления :-)
← →
Polevi (2003-08-12 09:41) [1]F7 пробовал ?
← →
Nikolay M. (2003-08-12 09:47) [2]
> Record not found or changed by another user
Пока не очень хочется вникать в лог и в логику, но поищи в инете, где вылезает эта ошибка для ADO. Для MS SQL такое случается, если есть тригеры, поэтому приходится во всех тригерах писать SET NOCOUNT ON.
Да, и почему у провайдера UpdateMode такой? Если есть первичный ключ, поставь upWhereKeyOnly. Только у Persistent-полей ClientDataSet-а и ADODataSet-а провайдерные флаги правильно выставь, какие - ключ, а что - апдейтить.
← →
AkaSaint (2003-08-12 19:20) [3]2Polevi: нет, а что это даст?
2Nikolay M. UpdateMode такой, чтобы при попытке изменить те же поля записи, которые успел изменить другой клиент, вылетала ошибка - чтобы клиент понял, что запись была изменена и перечитал ее. Если сделать upWhereKeyOnly, ошибки не будет.
← →
Nikolay M. (2003-08-13 10:15) [4]1) А как уходят записи? ApplyUpdates (тут сколько?)
2) Что лежит в DataSet события OnUpdateData перед возникновением ошибки?
← →
Polevi (2003-08-13 11:03) [5]>AkaSaint © (12.08.03 19:20) [3]
это позволит найти тебе место в исходном коде борланда, где эта ошибка возникает, а заодно и решение этой проблемы
← →
Polevi (2003-08-13 11:05) [6]>Nikolay M. © (12.08.03 09:47) [2]
крайне рекомендую писать это также в хранимых процедурах
← →
Nikolay M. (2003-08-13 11:18) [7]
> Polevi © (13.08.03 11:05) [6]
> крайне рекомендую писать это также в хранимых процедурах
Само собой, но здесь речь идет не о вызове процедуры, а об обновлении таблицы. Поэтому и упомянул только триггеры.
Поправка принята :)
← →
AkaSaint (2003-08-13 12:57) [8]2Nikolay M. 1)ApplyUpdates(-1)
2) Там лежат старые значения - те, которые этот клиент считал в последний раз.
2Polevi:
>это позволит найти тебе место в исходном коде борланда, где эта >ошибка возникает, а заодно и решение этой проблемы
Хотелось бы, конечно, обойтись без изучения кода Борланда.Изучать чужой код - дело неблагодарное, много требует времени.
Похоже, что ошибка имеет место, когда между попытками 2-х клиентов изменить одну и ту же запись проходит очень мало времени. Изменения, сделанные одним клиентом, несмотря на CommitTrans, еще не успевают вступить в силу. В результате, после появления ошибки, при перечитывании записи могут считаться опять старые данные (это видно из протокола, но не из приведенного мной куска). А могут считаться новые, но все равно что-то не срабатывает... Что?
← →
Polevi (2003-08-13 13:27) [9]>Изучать чужой код - дело неблагодарное, много требует времени.
Сколько тебе надо времени чтобы изучить данный код ?
Provider.pas
procedure TDataSetProvider.UpdateRecord(Source, Delta: TDataSet; BlobsOnly, KeyOnly: Boolean);
var
Field: TField;
i: Integer;
UseUpMode: TUpdateMode;
begin
if KeyOnly then
UseUpMode := upWhereKeyOnly
else
UseUpMode := UpdateMode;
if not FindRecord(Source, Delta, UseUpMode) then
DatabaseError(SRecordChanged);
...
...
...
end;
function TDataSetProvider.FindRecord(Source, Delta: TDataSet;
UpdateMode: TUpdateMode): Boolean;
procedure GetFieldList(DataSet: TDataSet; UpdateMode: TUpdateMode; List: TList);
var
i: Integer;
begin
for i := 0 to DataSet.FieldCount - 1 do
with DataSet.Fields[i] do
begin
if (DataType in [ftBytes, ftVarBytes]) or IsBlob or
(DataSet.Fields[i] is TObjectField) then continue;
case UpdateMode of
upWhereKeyOnly:
if pfInKey in ProviderFlags then List.Add(DataSet.Fields[i]);
upWhereAll:
if pfInWhere in ProviderFlags then List.Add(DataSet.Fields[i]);
upWhereChanged:
if (pfInKey in ProviderFlags) or (not VarIsEmpty(NewValue)) then
List.Add(DataSet.Fields[i]);
end;
end;
end;
var
i: Integer;
KeyValues: Variant;
Fields: string;
FieldList: TList;
IsDelta: BOOL;
begin
Result := False;
TPacketDataSet(Delta).DSBase.GetProp(dspropISDELTA, @IsDelta);
FieldList := TList.Create;
try
GetFieldList(Delta, UpdateMode, FieldList);
if FieldList.Count > 1 then
begin
KeyValues := VarArrayCreate([0, FieldList.Count - 1], varVariant);
Fields := "";
for i := 0 to FieldList.Count - 1 do
with TField(FieldList[i]) do
begin
if IsDelta then
KeyValues[i] := OldValue else
KeyValues[i] := Value;
if Fields <> "" then Fields := Fields + ";";
Fields := Fields + FieldName;
end;
Result := Source.Locate(Fields, KeyValues, []);
end
else if FieldList.Count = 1 then
begin
with TField(FieldList[0]) do
if IsDelta then
Result := Source.Locate(FieldName, OldValue, []) else
Result := Source.Locate(FieldName, Value, []);
end else
DatabaseError(SNoKeySpecified);
finally
FieldList.Free;
end;
end;
← →
Nikolay M. (2003-08-13 13:58) [10]Общее замечание, скорее мысли вслух - имхо, не стОит так мучать Access...
Может есть возможность поюзать этот кусок на MS SQL?
← →
Nikolay M. (2003-08-13 14:28) [11]
> Polevi ©
А можно к тебе в аську стукнуться? По ADO и провайдерским флагам как раз на днях непонятки случились...
← →
Polevi (2003-08-13 14:42) [12]>Nikolay M. © (13.08.03 14:28) [11]
стукнись
← →
AkaSaint (2003-08-16 17:19) [13]2Polevi: Выглядит и правда не так уж страшно. Но ответа на вопрос все равно не дает.
2Nikolay M. Я бы с радостью не мучал Access, да это все от бедности. Jet Access-то бесплатный, а вот MS SQL - не очень :-) А MSDE можно юзать только при условии не более 5 одновременных подключений, а это очень мало.
Страницы: 1 вся ветка
Форум: "Базы";
Текущий архив: 2003.09.08;
Скачать: [xml.tar.bz2];
Память: 0.49 MB
Время: 0.007 c