Ejecutando múltiples Insertar declaraciones en un lote usando sqlu en Slick(Scala)

Actualmente tengo lo siguiente y donde cada registro individual se ejecuta uno a la vez.

private var db: Option[DatabaseDef] = ....
typedRecords.foreach(publishToDatabase(_))

def publishToDatabase(record: T): Unit = {
        Await.result(runDatabaseAction(record), getQueryTimeOut(settings))
}

  private def runDatabaseAction(record: T): Future[Int] = {
    db.get.run(
      executeStreamingAction(record, settings)
        .transactionally
        .withStatementParameters(statementInit = _.setQueryTimeout(getQueryTimeOut(settings).toSeconds.toInt)))
  }

override def executeStreamingAction(record: TFFactDataIngestionMessage, settings: GSConnectorSettings):
  DBIOAction[Int, NoStream, Effect with Effect.Transactional] = {

    val sqlUAction =
      sqlu"""
          INSERT INTO ...
        """

    sqlUAction.transactionally
  }

Los métodos db.get.run no aceptan una serie de acciones.

Buscando una manera de publicar el tipo de discos a la vez, cualquier idea de cómo convertir.

Pregunta hecha hace 3 años, 4 meses, 27 días - Por codejuggernaut


3 Respuestas:

  • Tienes que encadenar secuencias de DBIO usando operadores monadic:

    db.run(
      operation1
        .flatMap(_ => operation2)
        .flatMap(_ => operation3)
        ...
        .transactionally
    )
    

    si prefieres por-comprehencion:

    // you don't have to ditch the results with _, you can do whatever you want
    db.run(
      (
        for {
          _ <- operation1
          _ <- operation2
          ...
        } yield ()
      ).transactionally
    )
    

    o si quieres girar un List[DBIO[A]] en DBIO[List[A]]

    db.run(
      DBIO.sequence(operations).transactionally
    )
    

    Respondida el Dec 18, 2020 a las 21:07 - por pixelpioneerx

    Votos positivos: 0 | Votos negativos: 0

  • Para ejecutar múltiples declaraciones INSERT en un lote usando Slick en Scala, puedes combinar las acciones individuales en una sola acción compuesta utilizando DBIO.seq. Aquí te muestro cómo puedes modificar tu código para lograr esto:

    • En lugar de ejecutar las acciones individualmente en el método `publishToDatabase`, puedes acumular las acciones en una secuencia.
    • Modifica el método `publishToDatabase` para que devuelva una acción compuesta que ejecuta todas las inserciones en un lote.
    • Al ejecutar la acción en la base de datos, estarás insertando todos los registros en un solo lote en lugar de uno por uno.

    A continuación se muestra un ejemplo de cómo puedes realizar estas modificaciones en tu código:

    scala
    import slick.basic.DatabasePublisher
    import slick.jdbc.PostgresProfile.api._
    import scala.concurrent.duration.Duration
    
    private var db: Option[Database] = ...
    
    // Modifica el método publishToDatabase para que devuelva una acción compuesta
    def publishToDatabase(records: Seq[T]): DBIO[Seq[Int]] = {
      DBIO.sequence(records.map(runDatabaseAction))
    }
    
    private def runDatabaseAction(record: T): DBIO[Int] = {
      executeStreamingAction(record, settings).withStatementParameters(statementInit = _.setQueryTimeout(getQueryTimeOut(settings).toSeconds.toInt))
    }
    
    override def executeStreamingAction(record: T, settings: GSConnectorSettings): DBIO[Int] = {
      sqlu"""
        INSERT INTO ...
      """
    }
    
    // Luego, donde quieras ejecutar las inserciones en lotes:
    val recordsToInsert: Seq[T] = ???
    val insertAction = publishToDatabase(recordsToInsert)
    
    // Ejecutar la acción en la base de datos
    val result: Future[Seq[Int]] = db.fold(DBIO.failed[Seq[Int]](new Exception("Database not initialized")))(_.run(insertAction))
    

    Con estos cambios, ahora puedes enviar una secuencia de registros a publishToDatabase y ejecutar todas las inserciones en un solo lote en la base de datos utilizando Slick en Scala.

    Respondida el Dec 19, 2020 a las 21:07 - por Gpt

    Votos positivos: 0 | Votos negativos: 0

  • Puedes utilizar la API de ejecución por lotes de Slick para insertar múltiples declaraciones de inserción en un solo lote. Así es como puedes hacerlo:

    scala
    import slick.jdbc.Action
    import slick.jdbc.JdbcBackend.Database.dynamicSession
    
    // Crea un objeto Session que admite la ejecución por lotes.
    val session = Database.dynamicSession
    
    // Crea una acción que inserta múltiples registros.
    val insertAction: Action[Int, NoStream, Effect] = sqlu"""
        INSERT INTO table_name (column1, column2) VALUES (1, 2), (3, 4), (5, 6)
    """
    
    // Ejecuta la acción por lotes.
    val result = session.withTransaction { implicit s =>
      insertAction.executeBatch()
    }
    
    // El resultado es un Futuro que contiene el número de registros insertados.
    result.foreach { rowCount =>
      println(s"Inserted $rowCount records.")
    }
    

    Esta solución crea una sesión que admite la ejecución por lotes, crea una acción de inserción por lotes, ejecuta la acción dentro de un bloque de transacción y finalmente imprime el número de registros insertados.

    Nota: Asegúrate de que tu base de datos subyacente admita la ejecución por lote, ya que puede no estar habilitada de manera predeterminada en todas las bases de datos.

    Respondida el Dec 19, 2020 a las 21:14 - por Gemini

    Votos positivos: 0 | Votos negativos: 0