All Downloads are FREE. Search and download functionalities are using the official Maven repository.

jio.jdbc.BatchOfOneEntity Maven / Gradle / Ivy

There is a newer version: 3.0.0-RC2
Show newest version
package jio.jdbc;

import jio.IO;
import jio.Lambda;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.time.Duration;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Executors;

/**
 * Represents a JDBC batch operation for inserting or updating multiple records in a database.
 *
 * @param  The type of input elements for the batch operation.
 */
class BatchOfOneEntity {

  final Duration timeout;
  final ParamsSetter setter;
  final String sql;
  final boolean continueOnError;
  final int batchSize;
  private final boolean enableJFR;
  private final String label;


  /**
   * Constructs a {@code BatchStm} instance with the specified settings.
   *
   * @param timeout         The maximum time in seconds that the batch operation should wait.
   * @param setter          A function to set parameters on a {@link java.sql.PreparedStatement}.
   * @param sql             The SQL statement for the batch operation.
   * @param continueOnError If true, the batch operation continues with the next batch even if one fails.
   * @param batchSize       The size of each batch.
   * @param enableJFR       Flag indicating whether Java Flight Recorder (JFR) events should be enabled.
   * @param label           The label to identify the batch operation in Java Flight Recording.
   */
  BatchOfOneEntity(Duration timeout,
                   ParamsSetter setter,
                   String sql,
                   boolean continueOnError,
                   int batchSize,
                   boolean enableJFR,
                   String label) {
    this.timeout = timeout;
    this.setter = setter;
    this.sql = sql;
    this.continueOnError = continueOnError;
    this.batchSize = batchSize;
    this.enableJFR = enableJFR;
    this.label = label;
  }

  /**
   * Builds and returns a {@code Lambda} representing the JDBC batch operation configured with the specified settings.
   * The resulting lambda is suitable for automatic resource management (ARM) and is configured to execute the batch
   * operation, process the result, and close the associated JDBC resources. The operations are performed on virtual
   * threads for improved concurrency and resource utilization.
   *
   * @param builder The {@code DatasourceBuilder} used to obtain the datasource and connections.
   * @return A {@code Lambda} representing the JDBC batch operation with a duration, input, and output. Note: The
   * operations are performed on virtual threads for improved concurrency and resource utilization.
   * @see BatchOfOneEntity#buildAutoClosable(DatasourceBuilder)
   */
  public Lambda, BatchResult> buildAutoClosable(DatasourceBuilder builder) {
    return inputs -> IO.task(
        () -> JfrEventDecorator.decorateBatch(
            () -> {
              try (var connection = builder.get()
                                           .getConnection()
              ) {
                try (var ps = connection.prepareStatement(sql)) {
                  ps.setQueryTimeout((int) timeout.toSeconds());
                  return process(inputs,
                                 ps,
                                 connection);
                }
              }
            },
            sql,
            enableJFR,
            label),
        Executors.newVirtualThreadPerTaskExecutor()
                            );
  }

  /**
   * Builds and returns a {@code ClosableStatement} representing a JDBC batch operation on a database. This method is
   * appropriate for use during transactions, where the connection needs to be managed externally. The lambda is
   * configured to bind parameters to its SQL, execute the batch operation, and map the result. The operations are
   * performed on virtual threads for improved concurrency and resource utilization.
   *
   * @return A {@code ClosableStatement} representing the JDBC batch operation with a duration, input, and output. Note:
   * The operations are performed on virtual threads for improved concurrency and resource utilization.
   * @see BatchOfOneEntity#buildClosable()
   */
  public ClosableStatement, BatchResult> buildClosable() {
    return (params, connection) ->
        IO.task(
            () -> JfrEventDecorator.decorateBatch(
                () -> {
                  try (var ps = connection.prepareStatement(sql)) {
                    ps.setQueryTimeout((int) timeout.toSeconds());
                    return process(params,
                                   ps,
                                   connection);
                  }
                },
                sql,
                enableJFR,
                label),
            Executors.newVirtualThreadPerTaskExecutor()
               );
  }

  private BatchResult process(List inputs,
                              PreparedStatement ps,
                              Connection connection) throws SQLException {
    List errors = new ArrayList<>();
    int executedBatches = 0, rowsAffected = 0, batchSizeCounter = 0;
    for (int i = 0; i < inputs.size(); i++) {
      try {
        setter.apply(inputs.get(i))
              .apply(ps);
        ps.addBatch();
        batchSizeCounter++;
        if (batchSizeCounter == batchSize || i == inputs.size() - 1) {
          executedBatches++;
          int[] xs = ps.executeBatch();
          for (int code : xs) {
            if (code >= 0) {
              rowsAffected += code;
            }
          }
          connection.commit();
          ps.clearBatch();
          batchSizeCounter = 0;  // Reset batchSizeCounter after each batch
        }
      } catch (SQLException e) {
        if (continueOnError) {
          errors.add(e);
          ps.clearBatch();
          batchSizeCounter = 0;
        } else {
          return new BatchFailure(inputs.size(),
                                  batchSize,
                                  executedBatches,
                                  rowsAffected,
                                  e);
        }
      }
    }
    if (errors.isEmpty()) {
      return new BatchSuccess(rowsAffected);
    } else {
      return new BatchPartialSuccess(inputs.size(),
                                     batchSize,
                                     executedBatches,
                                     rowsAffected,
                                     errors);
    }

  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy