Manejo de concurrencia de concurrencia en ASP.NET Core y Oracle

Los conflictos paralelos surgen debido al acceso simultáneo a un recurso compartido. En este artículo, se analizan formas de manejar los conflictos de simultaneidad mediante ASP.NET Core y Oracle. Se utilizará DocConnect para Oracle para conectarse a Oracle.

requisitos previos

Necesitará las siguientes herramientas para trabajar con ejemplos de código:

Índice

¿Qué es el procesamiento paralelo?

El procesamiento paralelo es un método para identificar y resolver problemas causados ​​por dos solicitudes simultáneas al mismo recurso. Es un mecanismo que permite que muchos usuarios accedan a los mismos datos al mismo tiempo, asegurando que los datos permanezcan consistentes en todas las solicitudes futuras.

El procesamiento paralelo es un método probado para detectar y resolver conflictos que surgen de solicitudes simultáneas al mismo recurso. En esencia, se puede utilizar para garantizar la integridad y la coherencia de los datos cuando varios usuarios simultáneos intentan acceder al mismo recurso al mismo tiempo.

Pueden ocurrir infracciones paralelas si tiene transacciones interdependientes, es decir, transacciones que dependen unas de otras e intentan acceder al mismo recurso. La transacción implica un conjunto de operadores unidos que se garantiza que se ejecutarán en su totalidad o se revertirán. Las transacciones contribuyen a la integridad y seguridad de los datos.

Existen dos enfoques para manejar los conflictos de concurrencia: estrategias de paralelismo optimista y estrategias de paralelismo pesimista. Ahora analicemos cómo funciona cada uno.

Paralelismo pesimista

El paralelismo pesimista implica bloquear las cadenas para evitar que otros usuarios cambien los datos y evitar inconsistencias en los datos. Esta estrategia hace que los registros sean inaccesibles desde el momento en que se recibieron por última vez hasta que se actualicen en la base de datos. Por lo tanto, si se modifica el registro, todos los demás cambios simultáneos en el mismo registro se retrasan hasta que se completa la operación actual y se bloquea el registro.

Este enfoque es una buena opción en un entorno con una gran competencia de datos. Puede aprovechar la simultaneidad pesimista en escenarios con tiempos de bloqueo cortos. Sin embargo, el paralelismo pesimista está mal escalado cuando los usuarios interactúan con los datos, lo que lleva al bloqueo de registros por períodos más largos.

Paralelismo optimista

En el modelo de paralelismo optimista, los registros no están bloqueados; si un usuario intenta editar una cadena, el programa determina si otro usuario cambió la cadena después de que se leyera por última vez en la memoria. El paralelismo optimista se usa a menudo en escenarios cuando los datos son escasos.

El paralelismo optimista aumenta la eficiencia al eliminar la necesidad de bloquear un registro que consume recursos adicionales del servidor. El paralelismo optimista mejora el rendimiento y escala mejor porque permite que el servidor atienda a más clientes en menos tiempo.

La versión optimista del paralelismo sigue la política de "últimas ganancias guardadas", lo que significa que el último valor modificado se almacena en la base de datos. En otras palabras, el último registro guardado "gana". Cabe señalar que el método optimista de gestión de la concurrencia sugiere que los conflictos de recursos provocados por el acceso simultáneo a un recurso compartido son poco probables, pero no imposibles. No es necesario que verifique las modificaciones simultáneas del mismo recurso (es decir, una entrada en una tabla de base de datos) con este método; el registro simplemente se reescribe.

Violación del paralelismo

En caso de la infracción del paralelismo, se volverán a leer los últimos datos en la base de datos y luego se realizará la tentativa repetida de actualización. Para comprobar si hay infracciones concurrentes, deberá asegurarse de que las entradas hayan cambiado desde que se leyó el programa anteriormente. Para que el control de paralelismo optimista funcione correctamente, su aplicación primero debe verificar la versión de la cadena antes de continuar con la actualización.

Cree un nuevo proyecto de API web de ASP.NET Core

Anteriormente, mencionamos las herramientas necesarias para pasar a escenarios prácticos. Es hora de usar estas herramientas.

Primero necesitamos crear un nuevo proyecto de API web de ASP.NET Core:

  1. Abra Visual Studio 2019.
  2. Hacer clic Crear un nuevo proyecto.
  3. Escoger Aplicación web ASP.NET Core y presiona próximo.
  4. Ingrese un nombre de proyecto y una ubicación para guardar este proyecto en su sistema. Opcionalmente, marque la casilla Coloque la solución y el proyecto en el mismo directorio. casilla de verificación
  5. Hacer clic Crear.
  6. У Crear una nueva aplicación web ASP.NET Core ventana, seleccione API como plantilla de proyecto.
  7. Escoger ASP.NET Core 5 o después.
  8. Desactivar Configurar para HTTPS y Habilitar la compatibilidad con Docker opciones (desmarcar).
  9. Dado que no usaremos la autenticación en este ejemplo, especifique la autenticación como Sin autenticacion.
  10. Hacer clic Crear para completar el proceso.

Usaremos este proyecto en este artículo.

Implementar procesamiento paralelo en ASP.NET Core y Oracle

Si varios usuarios intentan cambiar la misma información al mismo tiempo, debe tener una forma de evitar que los cambios de un usuario interfieran con los cambios de otros usuarios. El control paralelo es el proceso de detección y resolución de cambios en la base de datos que realizan muchos usuarios simultáneamente.

Cree una nueva tabla de base de datos.

Primero, creemos una nueva tabla de base de datos en Oracle. El siguiente fragmento de código se puede usar para crear una nueva tabla llamada producto en Oracle.

create table product
  (
    product_id number primary key,
    product_name varchar2(50) not null,
    price double precision not null
  );

A continuación, inserte varias entradas en la tabla de productos utilizando el siguiente escenario:

insert into product values(1,'Lenovo Laptop',1000.00);
insert into product values(2,'HP Laptop',1000.00);
commit;

Instalar paquetes NuGet

Para comenzar, debe instalar el paquete dotConnect para Oracle en su proyecto. Puede instalarlo desde la herramienta NuGet Package Manager en Visual Studio o desde la consola de NuGet Package Manager usando el siguiente comando:

PM> Install-Package Devart.Data.Oracle

Si la instalación es exitosa, todos están listos para comenzar a usar dotConnect para Oracle.

Creación de una conexión de Oracle

Ahora ingrese las credenciales de la base de datos de Oracle en su aplicación para conectarse a la base de datos. Puede guardar esta información, que puede personalizarse guardándola también en el archivo de configuración de la aplicación.

El fragmento de código siguiente ilustra cómo puede crear una instancia de OracleConnection:

String connectionString = "User Id=Your user Id; Password=Your password; Server = localhost; License Key = Specify your license key here; ";
OracleConnection oracleConnection = new OracleConnection(connectionString);

Debe incluir el siguiente espacio de nombres en su programa:

using Devart.Data.Oracle;

Actualizar datos

Consideremos ahora cómo simular el paralelismo optimista en ADO.NET usando dotConnect para Oracle. Aquí aprovecharemos el modo deshabilitado.

El siguiente fragmento de código ilustra cómo puede usar OracleDataAdapter para simular el paralelismo optimista en ADO.NET.

OracleDataAdapter oracleAdapter = new OracleDataAdapter();
oracleAdapter.SelectCommand = new OracleCommand("select * from product", oracleConnection);

DataSet dataSet = new DataSet();
oracleAdapter.Fill(dataSet);

oracleAdapter.UpdateCommand = new OracleCommand("UPDATE product Set id = :id, " + 
"name = :name WHERE id = :oldid AND name = :oldname", oracleConnection);
oracleAdapter.UpdateCommand.Parameters.Add(":id", OracleDbType.Integer, 5, "id");
oracleAdapter.UpdateCommand.Parameters.Add(":name", OracleDbType.VarChar, 50, "name");

OracleParameter parameter = oracleAdapter.UpdateCommand.Parameters.Add(":oldid", OracleDbType.Integer, 5, "id");
parameter.SourceVersion = DataRowVersion.Original;
parameter = oracleAdapter.UpdateCommand.Parameters.Add(":oldname", OracleDbType.NVarChar, 50, "name");
parameter.SourceVersion = DataRowVersion.Original;
dataSet.Tables[0].Rows[0]["name"] = "DELL Laptop";

oracleAdapter.Update(dataSet);

El fragmento de código anterior muestra cómo puede configurar UpdateCommand OracleDataAdapter para verificar el paralelismo optimista. Observe cómo se usó el elemento "dónde" del comando de actualización para verificar cualquier violación de paralelismo optimista que pudiera haber ocurrido.

Cree una clase llamada Producto a a continuación:

public class Product
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public double Price { get; set; }                
    }

Usaremos esta clase como nuestro modelo en este ejemplo.

Crear un método de acción en la clase ProductController

Cree una nueva clase de controlador en su proyecto llamada ProductController. La siguiente lista de códigos ilustra cómo puede escribir un método de acción del controlador para actualizar una entrada en una tabla de productos.

[HttpPut]
public IActionResult Put([FromBody] Product product) {
  string connectionString = "User Id=Your user Id;Password=Your password; Server = localhost; License Key = Your License Key";

  try {
    using(OracleConnection oracleConnection = new OracleConnection(connectionString)) {
      try {
        OracleDataAdapter oracleAdapter = new OracleDataAdapter();
        oracleAdapter.SelectCommand = new OracleCommand("select * from product where id  
        = :id", oracleConnection);
        oracleAdapter.SelectCommand.Parameters.Add("id", product.Id);

        DataSet dataSet = new DataSet();
        oracleAdapter.Fill(dataSet);

        if (dataSet.Tables[0].Rows.Count == 0) return NotFound();

        oracleAdapter.UpdateCommand = new OracleCommand("update product set name = 
        :name "+
        "WHERE id = :oldid AND name = :oldname", oracleConnection);
        oracleAdapter.UpdateCommand.Parameters.Add(":name", OracleDbType.VarChar, 50, 
        "name");

        OracleParameter parameter = 
        oracleAdapter.UpdateCommand.Parameters.Add(":oldid", product.Id);
        parameter.SourceVersion = DataRowVersion.Original;

        parameter = oracleAdapter.UpdateCommand.Parameters.Add(":oldname", 
        OracleDbType.VarChar, 50, "name");
        parameter.SourceVersion = DataRowVersion.Original;

        dataSet.Tables[0].Rows[0]["name"] = product.Name;

        oracleAdapter.Update(dataSet);
      } catch (DBConcurrencyException ex) {
        Debug.WriteLine(ex.Message);
        return BadRequest("Db Concurrency Violation");
      }

      if (oracleConnection.State != ConnectionState.Closed) oracleConnection.Close();
    }
  } catch (Exception ex) {
    Debug.WriteLine(ex.Message);
    return BadRequest("Error...");
  }

  return Ok("1 record updated...");
}

Recuerde incluir el siguiente espacio de nombres en el archivo ProductController.cs:

using Devart.Data.Oracle;

Complete la solicitud

Ejecute la herramienta Postman y ejecute el punto final después de especificar la URL como se muestra a continuación.

Observe el mensaje de texto "1 registro actualizado..." en la respuesta.

Establezca un punto de interrupción en la llamada al método Update de la clase OracleDataAdapter en su método de acción. Ahora haga clic en el mismo punto final de nuevo.

Ejecute los siguientes comandos para actualizar el registro explícitamente:

update product set name="DELL Laptop" where id = 1;
commit;

Ahora, si presiona F10, se le presentará la siguiente excepción:

Una vez que haga clic en F5, podrá ver la respuesta devuelta a Postman como se muestra a continuación:

Resumen

En esta publicación, hemos implementado el procesamiento paralelo con OracleDataAdapter en modo deshabilitado. También puede implementar el paralelismo en modo conectado y aprovechar la versión de cadena utilizando la columna de marca de tiempo en su base de datos. Después de actualizar el registro, la versión de la cadena cambiará y podrá verificar si la versión de la cadena de registro ha cambiado durante la operación de actualización en la base de datos.

Artículos de interés

Subir