Backend del servicio web en la base de datos. Cómo construir lógica empresarial y crear un relé de microservicio para la API frontend

Este artículo le mostrará cómo organizar un diseño sencillo de la lógica empresarial de servicios web en una base de datos PL-SQL incorporada.



Te diré cómo hacer un servicio de retransmisión simple para la interfaz (un ejemplo estará en php), así como lo fácil que es diseñar una API analógica en la base y registrarla para retransmitirla a la interfaz.



PD: un ejemplo de backend y frontend estará en PHP, base de datos firebird. Pero esto no es necesario, puede utilizar cualquier lenguaje de programación y cualquier base de datos.


PD: Te pido que no tires el sombrero. Sé que ahora no es popular, por ciertas razones sociales, hay más especialistas en PHP o Python en el mercado que programadores SQL, son más baratos, a todos les encanta el ORM. Se cree que al establecer la lógica en la base de datos, es más difícil organizar una arquitectura de microservicio. Más difícil de administrar el control de versiones. Go compila y debería ejecutarse más rápido que una base de datos. Es popular colocar la lógica de negocios en marcos php, etc.

Hay muchas razones y todos tienen argumentos de un lado y del otro, y cada uno puede ser discutido profundamente.



Pero este artículo es para aquellos que quieran configurar la lógica empresarial en la base de datos . No hay ningún propósito aquí para promover tal método. Sea correcto en los comentarios.


En general, el método es muy sencillo y molesto en cuanto a velocidad. Si escribe una retransmisión de microservicio competente y usa activamente tablas de servicio en la base de datos, entonces registrar nuevas API requiere solo una tabla de servicio del formulario:



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





Por ejemplo:



imagen



El esquema es el siguiente:



imagen



Aquí consideraremos cómo organizar el trabajo del microservicio "Servicio para interfaz". Daré un



ejemplo de una interfaz en 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));
}

      
      





Un ejemplo de un procedimiento llamado en 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
      
      





Ahora entendemos cómo un relé de microservicio comprenderá que es necesario realizar este procedimiento en particular, cómo comprenderá qué parámetros tiene, cómo lo extraerá. Daré un código de ejemplo, detalles en los comentarios en el 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;   
   
}

?>

      
      





Lo que obtenemos al final.



1) Escribimos un relé de microservicio 1 vez. Todo el resto del diseño de la arquitectura de backend se lleva a cabo en la base de datos. En PHP (o Go, Python, cuál será el microservicio) ya no escalamos.



Por ejemplo, se necesitaba una nueva característica en el sitio: se está realizando una interfaz, se está realizando un procedimiento. El procedimiento se registra en la placa y el frontend por su número de registro se refiere a la API de microservicio. TODO.



Recomiendo escribir un relé de microservicio en Go compilado y mucho más rápido. La ventaja es que solo necesita escribirse una vez y el programa no es complicado. Además, será un elemento muy cargado, al que se producirán llamadas intensivas.



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



2) Todo el procesamiento entra en procedimientos: obtenemos elementos compilados que procesan todo a nivel de base de datos y producen un RESULTADO. Aquellos. si la operación consta de varios seleccionar, insertar, actualizar, etc. no enviamos datos a través de la red al backend, sino que los procesamos inmediatamente en la base de datos.



Además, un procedimiento es un elemento compilado con un plan de consulta generado. Tampoco se gastan recursos en esto.



3) Microservicio-relé, para formar el procedimiento, se remite a la base de datos 4 veces.



1. Obtenga su nombre

2. Obtenga sus parámetros salientes

3. Obtenga sus parámetros entrantes

4. Ejecuta el procedimiento

4 veces, porque consideramos un método universal. Esto se puede reducir a una vez.



Cómo:



1. Se puede almacenar localmente en un editor de texto en un servidor web, por ejemplo. Periódicamente simplemente extrayendo esta tabla y actualizándola cuando se agrega una nueva.

2.3. Del mismo modo, puede almacenarlo localmente, extrayéndolo todo cuando se actualiza algo.



4) ¡No todo el backend se puede hacer en la base de datos! Esta es una parte esencial de todo, pero uno debe guiarse por consideraciones de conveniencia .



Por ejemplo, algunos chats, mailings, etc. Los aspectos de la vida de un servicio web, por supuesto, deben realizarse como microservicios separados en el lenguaje de programación más conveniente para esto. ¡No es necesario transferir toda la lógica del servicio web a la base a cualquier precio! ¡Necesita transferir solo la parte que sea conveniente para esto!



All Articles