Backend do serviço web no banco de dados. Como construir uma lógica de negócios e criar uma retransmissão de microsserviço para a API de front-end

Este artigo mostrará como organizar um design fácil de lógica de negócios de serviço da Web em um banco de dados PL-SQL incorporado.



Vou te contar como fazer um serviço de retransmissão simples para o frontend (um exemplo será em php), bem como como é fácil projetar uma API analógica na base e registrá-la para retransmissão para o frontend.



PS: um exemplo de backend e frontend será em PHP, banco de dados firebird. Mas isso não é necessário, você pode usar qualquer linguagem de programação e qualquer banco de dados.


PS: Peço que não jogue o chapéu. Eu sei que agora não é popular, por certos motivos sociais, existem mais especialistas em PHP ou Python no mercado do que programadores SQL, eles são mais baratos, todo mundo adora ORM. Acredita-se que ao estabelecer a lógica no banco de dados, é mais difícil organizar uma arquitetura de microsserviço. Mais difícil de gerenciar o controle de versão. Go compila e deve ser executado mais rápido do que um banco de dados. É popular estabelecer lógica de negócios em estruturas de php, etc.

As razões são muitas e todos têm argumentos de um lado e do outro, e cada um pode ser discutido profundamente.



Mas este artigo é para aqueles que desejam definir a lógica de negócios no banco de dados . Não há nenhum propósito aqui para promover tal método. Por favor, esteja correto nos comentários.


Em geral, o método é muito simples e irritante em termos de velocidade. Se você escrever uma retransmissão de microsserviço competente e usar ativamente tabelas de serviço no banco de dados, o registro de novas APIs requer apenas uma tabela de serviço no formato:



CREATE TABLE DFM_PROC (
    ID           INTEGER NOT NULL,
    NAME         VARCHAR(70) NOT NULL,
    DISCRIPTION  VARCHAR(1000)
);
      
      





Por exemplo:



imagem



O esquema é o seguinte:



imagem



Aqui consideraremos como organizar o trabalho do microsserviço "Serviço para interface". Vou dar um



exemplo de um frontend em php



function ser1($proc_id,$json)
{
//   
$post='hash='.$_SESSION['sess_id'].'&user_id='.$_SESSION['id_user'].'&proc_id='.$proc_id.'&json='.base64_encode($json);

// 
$url = 'http://192.168.128.1/ser.php';
	 
$ch = curl_init();
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_URL, $url);
    curl_setopt($ch, CURLOPT_POST , true);
    curl_setopt($ch, CURLOPT_POSTFIELDS ,$post);
    $result = curl_exec($ch);
    $arr_res=json_decode($result,true);			
curl_close($ch);
	
return $arr_res;
}

//          
//       
// 4 -      
if (isset($_POST['go_new_prof']))
{
    unset($arr);
    $arr['0']=$_SESSION['id_user'];
    $arr['1']=(int)$_GET['tp'];
    $arr['2']=(int)$_POST['lang_list'];
    $arr_prof=ser1(4,json_encode($arr));
}

      
      





Um exemplo de um procedimento chamado em SQL



create or alter procedure DFM_PROF_ADD (
    USER_ID smallint,
    TYPE_ varchar(10),
    LANG smallint)
as
begin

  INSERT INTO DFM_PROFILES (USER_ID, TYPE_, LANG)
    VALUES (:USER_ID, :TYPE_, :LANG);
  suspend;

end
      
      





Agora entendemos como um relé de microsserviço entenderá que é necessário realizar esse procedimento específico, como entenderá quais parâmetros ele possui, como o puxará. Vou dar um exemplo de código, detalhes nos comentários do código




<?php

$proc_id=(int)$_POST['proc_id'];
$json= base64_decode($_POST['json']);

$arr_json = json_decode($json,true);

// JSON
switch (json_last_error()) {
   case JSON_ERROR_NONE:
      $err = null;
   break;
   case JSON_ERROR_DEPTH:
      $err = '   ';
   break;
   case JSON_ERROR_STATE_MISMATCH:
      $err = '     ';
   break;
   case JSON_ERROR_CTRL_CHAR:
      $err = '  ';
   break;
   case JSON_ERROR_SYNTAX:
      $err = ' ,   JSON';
   break;
   case JSON_ERROR_UTF8:
      $err = '  UTF-8,   ';
   break;
   default:
      $err = ' ';
   break;
}

//     JSON
if ($err==null) 
{
   
   //         ID
   $user_id=1;

   //     ID
   $sql_proc = "select p.name from DFM_PROC p where p.id=".$proc_id;
   $res_proc = ibase_query($dbh, $sql_proc);
   $prom_proc = ibase_fetch_row($res_proc);
   
   //     
   $sql_in='select ';
   
   //   , 
   //   RDB$PROCEDURE_PARAMETERS       
   $sql = 'select pp.rdb$parameter_number, pp.rdb$parameter_name from DFM_PROC p
left join RDB$PROCEDURE_PARAMETERS pp on pp.rdb$procedure_name=UPPER(p.name)
where p.id='.$proc_id.' and pp.rdb$parameter_type=1 --
order by pp.rdb$parameter_number';
   $res = ibase_query($dbh, $sql);
   $i_cou_out=0;
   while($prom = ibase_fetch_row($res))
   {
      //p. -     
      $i_cou_out++;
      if ($prom[0]>0) $sql_in.=','; 
      $sql_in.='p.'.$prom[1];
      
      $name_out[$prom[0]]=$prom[1];
   }
   
   //            -   
   $sql_in.=' from '.$prom_proc[0];
   
   //    ,    ,   execute procedure
   if ($i_cou_out==0) $sql_in='execute procedure '.$prom_proc[0];
   
   //      
   $sql = 'select
pp.rdb$parameter_number,
pp.rdb$parameter_name,
case
   when f.rdb$field_type=7 then 1 --smalint
   when f.rdb$field_type=8 then 2 --integer
   when f.rdb$field_type=16 and f.rdb$field_scale=0 then 3 --bigint
   when f.rdb$field_type=16 and f.rdb$field_scale<0 then 4 --frloat
   when f.rdb$field_type=12 then 5 --date
   when f.rdb$field_type=13 then 6 --time
   when f.rdb$field_type=35 then 7 --timestamp
   when f.rdb$field_type=37 then 8 --varcahr
end,
f.rdb$field_type, -- 
f.rdb$character_length, -- 
f.rdb$field_precision, -- 
f.rdb$field_scale -- 
from DFM_PROC p
left join RDB$PROCEDURE_PARAMETERS pp on pp.rdb$procedure_name=UPPER(p.name)
left join RDB$FIELDS f on f.rdb$field_name=pp.rdb$field_source
where p.id='.$proc_id.' and pp.rdb$parameter_type=0 --
order by pp.rdb$parameter_number';
   $res = ibase_query($dbh, $sql);
            
   $i_cou=0;
   while($prom = ibase_fetch_row($res))
   {
      $i_cou++;
      if ($prom[0]>0)  $sql_in.=','; else $sql_in.='(';
      
      
      if (($prom[2]==5)or($prom[2]==6)or($prom[2]==7)or($prom[2]==8))
         //    
         //    null
         if ($arr_json[$prom[0]]=='')
            $sql_in.="null";
         else
            $sql_in.="'".($arr_json[$prom[0]])."'";
      else
         //   
         if ($arr_json[$prom[0]]=='')
            $sql_in.="null";
         else
            $sql_in.=($arr_json[$prom[0]]);
      
   }
   
   //   
   if ($i_cou_out==0)
      {if ($i_cou>0) $sql_in.=')';}
   else
      {if ($i_cou>0) $sql_in.=') p'; else $sql_in.=' p';}
      //   p.   
   
   // 
   $res_in = ibase_query($dbh, $sql_in);
   
   
   if ($i_cou_out==0)
   {
      //    execute procedure
      $json_out='{
"error_json":"",
"error_code_json":"",
"result":" execute procedure",
"result_code":0
}'; 
   }
   else
   {
      //  json  
      $i_json=0;
      $json_out='{';
      while($prom_in = ibase_fetch_row($res_in))
      {
         if ($i_json>0) $json_out.=',';
         $json_out.='"'.$i_json.'":{';
         foreach($prom_in as $k => $v)
         {
            if ($k>0) $json_out.=',
';
            $json_out.='"'.trim($name_out[$k]).'":"'.$v.'"';
         }
         $json_out.='}';
         $i_json++;
      }
      $json_out.='}';
   }
   
   //      -   ,  ,  
   if (ibase_errmsg()=='')
   {
      //  
      echo $json_out;   
   }
   else
   {
      //   
      $err_json='{
"error_json":"'.$err.'",
"error_code_json":'.json_last_error().',
"result":"'.str_replace('"','\'',ibase_errmsg()).'",
"result_code":2,
"sql_err":"'.$sql_in.'"}';
      echo $err_json;
   }
   
            
}
else 
{
   //    JSON
   $err_json='{
"error_json":"'.$err.'",
"error_code_json":'.json_last_error().',
"result":" json",
"result_code":3
}';
   echo $err_json;   
   
}

?>

      
      





O que obtemos no final.



1) Escrevemos um relé de microsserviço 1 vez. Todo o resto do design da arquitetura de backend ocorre no banco de dados. Em PHP (ou Go, Python, qual será o microsserviço), não escalamos mais.



Por exemplo, um novo recurso era necessário no site - um frontend está sendo feito, um procedimento está sendo feito. O procedimento é registrado na placa e o frontend por seu número de registro chama a API de microsserviço. TUDO.



Eu recomendo escrever um relé de microsserviço em Go conforme compilado e muito mais rápido. A vantagem é que só precisa ser escrito uma vez e o programa não é complicado. Além disso, será um elemento altamente carregado, para o qual ocorrem chamadas intensivas.



Biblioteca para conectar firebird a goland: https://github.com/nakagami/firebirdsql .



2) Todo o processamento vai para procedimentos - obtemos elementos compilados que processam tudo no nível do banco de dados e produzem um RESULTADO. Essa. se a operação consiste em vários selecionar, inserir, atualizar, etc. não direcionamos dados pela rede para o back-end, mas os processamos imediatamente no banco de dados.



Além disso, um procedimento é um elemento compilado com um plano de consulta gerado. Nenhum recurso é gasto nisso também.



3) Microsserviço-relé, para formar o procedimento, refere-se ao banco de dados 4 vezes.



1. Obtenha seu nome

2. Obtenha seus parâmetros de saída

3. Obtenha seus parâmetros de entrada

4. Execute o procedimento

4 vezes, porque consideramos um método universal. Isso pode ser reduzido para uma vez.



Como:



1. Pode ser armazenado localmente em um editor de texto em um servidor web, por exemplo. Periodicamente, apenas puxando esta tabela e atualizando quando uma nova é adicionada.

2.3. Da mesma forma, você pode armazená-lo localmente puxando-o por completo quando algo for atualizado.



4) Nem todo backend pode ser feito no banco de dados! Esta é uma parte essencial de tudo, mas devemos nos guiar por considerações de conveniência .



Por exemplo, alguns chats, mailings, etc. aspectos da vida de um serviço da web, é claro, devem ser feitos como microsserviços separados na linguagem de programação mais conveniente para isso. Não é necessário transferir toda a lógica do serviço web para a base a qualquer custo! Você precisa transferir apenas a parte que for conveniente para isso!



All Articles