Ver Mensaje Individual
  #1  
Antiguo 23-02-2022
APO APO is offline
Miembro
 
Registrado: feb 2008
Posts: 129
Reputación: 19
APO Va por buen camino
Problema concurrencia transacciones SQL SERVER

Buenas tardes,
Escribo este hilo, porque después de muchas horas investigando y leer bastantes hilos del foro, no doy con la solución.

Os explico el problema: tengo una función que reserva el código de una tabla (mira el más alto y devuelve el siguiente), para después yo poder hacer una serie de operaciones y luego insertar un registro en esa tabla con ese código de reserva. Para reservar ese código, lo que hago es un INSERT en esa tabla con el resto de campos vacíos que después rellenaré, para tener la seguridad de tener ese código reservado. La función devuelve True si ha podido realizar la reserva correctamente o False si ha dado algún error. Y el problema viene ahora, y es que varias veces me ha pasado que la función me ha devuelto el mismo código de reserva que otra reserva realizada previamente. No lo entiendo, porque si hago la reserva con un INSERT, ¿cómo es que no ha dado una excepción? En cambio me ha devuelto un código repetido y a True. Es como si el SQL SERVER no se hubiese enterado del INSERT. También lo he probado con los diferentes IsolationLevel de la conexión (ilCursorStability, ilReadUncommitted, ilReadCommitted, etc...) pero con el mismo resultado.

Os pongo el código por si veis algo que está mal.

Agradecería cualquier ayuda, sugerencia, lo que sea... Muchas gracias!

Código Delphi [-]
function TfrmPrincipal.ReservarCodigoAsiento(var Asiento: integer): boolean;
var
   qExec: TADOQuery;
   sql: string;
begin
   Result:=False;

   qExec:=TADOQuery.Create(Self);
   qExec.Connection:=Con001; //Asignamos conexión
   qExec.ParamCheck:=False;

   //Iniciamos transacción
   if Con001.InTransaction then Con001.RollbackTrans;
   Con001.BeginTrans;

   if Con001.InTransaction then
   begin
      try
         Asiento:=BuscarProximoCodigoAsiento(Date);
         //La clave primaria son los 3 campos CODIGO,CODIGO_LINEA,ANYO
         sql:='INSERT INTO TABLA (CODIGO,CODIGO_LINEA,ANYO, OTROS CAMPOS ....) VALUES('+
              IntToStr(Asiento)+','+
              '0,'+
              '2022',
              Los demás campos los dejo a blanco);
          qExec.Close;
          qExec.SQL.Text:=sql;
          qExec.ExecSQL;

          Con001.CommitTrans;

          Result:=True;
      except
         on E: Exception do
         begin
            Result:=False;
            if Con001.InTransaction then Con001.RollbackTrans;
         end;
      end;
   end;

   qExec.Close;
   qExec.Free;
end;

function TfrmPrincipal.BuscarProximoCodigoAsiento(FechaAsiento: TDateTime): integer;
var
   qExec: TADOQuery;
   sql: string;
begin
   Result:=2;
   qExec:=TADOQuery.Create(Self);
   qExec.Connection:=Con001;
   qExec.ParamCheck:=False;

   //Asignamos siguiente código de asiento
   sql:='SELECT  MAX(CODIGO) AS CODIGO '+
        'FROM    TABLA '+
        'WHERE  (ANYO = '+FormatDateTime('yyyy',FechaAsiento)+')';
   qExec.SQL.Text:=sql;
   qExec.Open;
   if not qExec.Eof then
   begin
      if not qExec.FieldByName('CODIGO').IsNull then
         Result:=qExec.FieldByName('CODIGO').AsInteger+1;
   end;

   qExec.Close;
   qExec.Free;
end;
Responder Con Cita