Bulk Processing - Insert Rows Using Collections of PL/SQL Records

Example Description

  • A table is created to store the data (the same table as the previous example).
  • The collection of PL/SQL Record element is defined in package specification.
  • The bulk 'FORALL' command inserts all rows at once.
  • A timer+counter determines the performance.

Create Table Statement

Table : BULK_PROCESSING_TABLE
create table bulk_processing_table
(
n    number not null,
d    date not null,
s    varchar2(100) not null
);

PL/SQL Package Specification

PL/SQL Package Specification : BULK_PLSQL_RECORD
create or replace package bulk_plsql_record
/**
 * Bulk collection demo package demonstration of collection of PL/SQL Records elements.
 */
as

type plsql_record is record (
  n    number,
  d    date,
  s    varchar2(100)
);
type table_plsql_record is table of plsql_record;

/**
 * Bulk collection demo with PL/SQL Record element.
 * 
 * @param i_table_plsql_record List of record elements of type 'plsql_record' to insert into table 'bulk_processing_table'.  
 */
procedure doit
(
  i_table_plsql_record   in table_plsql_record 
);

end bulk_plsql_record;

PL/SQL Package Implementation

PL/SQL Package Body : BULK_PLSQL_RECORD
create or replace package body bulk_plsql_record
as

/**
 * Bulk collection demo with PL/SQL Record element.
 * 
 * @param i_table_plsql_record List of record elements of type 'plsql_record' to insert into table 'bulk_processing_table'.  
 */
procedure doit
(
  i_table_plsql_record   in table_plsql_record 
)
is
begin
  forall i in 1..i_table_plsql_record.count
    insert into bulk_processing_table
      (n,d,s)
      values
      (i_table_plsql_record(i).n, i_table_plsql_record(i).d, i_table_plsql_record(i).s);
end doit;

end bulk_plsql_record;

Factory API : Calling the PL/SQL package

Using the static factory to get the remote service.
Java Calling Class : BulkCollectionPlSqlRecordFactoryApi.java
package plsql_workbench_examples.factoryapi;

import java.sql.Date;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;

import factory.ExamplesRPCFactory;
import plsql_workbench_examples.timer.TimerCounter;
import service.BulkPlsqlRecordService;
import transferobject.BulkPlsqlRecordTO;

public class BulkCollectionPlSqlRecordFactoryApi {
  private final static int ELEMENTS = 50000;

  public static void main(String[] args)
  {
    try {
      // set database credentials and configuration parameters
      System.setProperty("dbw_examples.url", "jdbc:oracle:thin:@192.168.0.102:1521/orcl");
      System.setProperty("dbw_examples.username", "dbw_examples");
      System.setProperty("dbw_examples.password", "dbw_examples");
      System.setProperty("dbw_examples.poolsize.min", Integer.toString(3));
      System.setProperty("dbw_examples.poolsize.max", Integer.toString(10));

      // getting the service
      BulkPlsqlRecordService service = ExamplesRPCFactory.getBulkPlsqlRecordService();

      // generating 50000 elements to transfer to the stored procedure 
      List<BulkPlsqlRecordTO.PlsqlRecord> list = new ArrayList<>(ELEMENTS);
      for (int i = 0; i < ELEMENTS; i++) {
        BulkPlsqlRecordTO.PlsqlRecord o = new BulkPlsqlRecordTO.PlsqlRecord();
        o.d = new Date(System.currentTimeMillis() + (long) (Math.random() * Integer.MAX_VALUE));
        o.s = UUID.randomUUID().toString();
        o.n = (int) (Math.random() * Integer.MAX_VALUE);
        list.add(o);
      }

      // timer to check the throughput
      TimerCounter tc = new TimerCounter();

      // calling the stored procedure
      service.doit(list);

      // print out throughput
      System.out.println(tc.perSecond("collection of pl/sql record element bulk performance (first call)", ELEMENTS));

      // calling the stored procedure
      service.doit(list);

      // print out throughput
      System.out.println(tc.perSecond("collection of pl/sql record element bulk performance (second call)", ELEMENTS));
    }
    catch (Exception e) {
      e.printStackTrace();
    }
  }
}

Spring API : Calling the PL/SQL package

Using Spring annotation to inject the service and call the remote service.
Java Calling Class : BulkCollectionPlSqlRecordSpringApi.java
package plsql_workbench_examples.springapi;

import java.sql.Date;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.support.GenericApplicationContext;
import org.springframework.stereotype.Component;

import plsql_workbench_examples.timer.TimerCounter;
import service.BulkPlsqlRecordService;
import transferobject.BulkPlsqlRecordTO;

@Component
public class BulkCollectionPlSqlRecordSpringApi {
  private final static int       ELEMENTS = 50000;

  @Autowired
  private BulkPlsqlRecordService bulkPlsqlRecordService;

  public static void main(String[] args)
  {
    // set database credentials and configuration parameters
    System.setProperty("dbw_examples.url", "jdbc:oracle:thin:@192.168.0.102:1521/orcl");
    System.setProperty("dbw_examples.username", "dbw_examples");
    System.setProperty("dbw_examples.password", "dbw_examples");
    System.setProperty("dbw_examples.poolsize.min", Integer.toString(3));
    System.setProperty("dbw_examples.poolsize.max", Integer.toString(10));

    // Register Spring Beans, Spring Context and call demo method 
    try (GenericApplicationContext ctx = BaseSpringConfig.getCtx(BulkCollectionPlSqlRecordSpringApi.class)) {
      ctx.getBean(BulkCollectionPlSqlRecordSpringApi.class).runDemo();
    }
  }

  private void runDemo()
  {
    try {
      // generating 50000 elements to transfer to the stored procedure 
      List<BulkPlsqlRecordTO.PlsqlRecord> list = new ArrayList<>(ELEMENTS);
      for (int i = 0; i < ELEMENTS; i++) {
        BulkPlsqlRecordTO.PlsqlRecord o = new BulkPlsqlRecordTO.PlsqlRecord();
        o.setD(new Date(System.currentTimeMillis() + (long) (Math.random() * Integer.MAX_VALUE)));
        o.setS(UUID.randomUUID().toString());
        o.setN((int) (Math.random() * Integer.MAX_VALUE));
        list.add(o);
      }

      // timer to check the throughput
      TimerCounter tc = new TimerCounter();

      // calling the stored procedure
      bulkPlsqlRecordService.doit(list);

      // print out throughput
      System.out.println(tc.perSecond("collection of pl/sql record element bulk performance (first call)", ELEMENTS));

      // calling the stored procedure
      bulkPlsqlRecordService.doit(list);

      // print out throughput
      System.out.println(tc.perSecond("collection of pl/sql record element bulk performance (second call)", ELEMENTS));
    }
    catch (Exception e) {
      e.printStackTrace();
    }
  }
}