Bulk Processing - Inserting Rows Using PL/SQL Tables

Example Description

  • A table is created to store the data (the same table as the previous example).
  • In the package specification the PL/SQL table types and the procedure is declared.
  • The procedure of the package inserts all rows at once with the 'FORALL' command.
  • A timer+counter determines the performance in the Java calling class.

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_TABLE
create or replace package bulk_plsql_table
/**
 * Bulk collection demo package demonstration in package defined PL/SQL tables.
 */
as

/** PL/SQL table type definitions */
type plsql_table_number is table of number index by pls_integer;
type plsql_table_date is table of varchar2(8) index by pls_integer;
type plsql_table_varchar is table of varchar2(100) index by pls_integer;

/**
 * Bulk collection demo with three input parameter of PL/SQL table.
 * Because only number and varchar2 elements are supported, the date value is converted to varchar2.
 * 
 * @param i_plsqltab_number List of number values to insert into table 'bulk_processing_table'.  
 * @param i_plsqltab_date List of date values to insert into table 'bulk_processing_table'.  
 * @param i_plsqltab_varchar List of varchar2 values to insert into table 'bulk_processing_table'.  
 */
procedure bulk_plsql_table
(
  i_plsqltab_number   in plsql_table_number, 
  i_plsqltab_date     in plsql_table_date, 
  i_plsqltab_varchar  in plsql_table_varchar
);

end bulk_plsql_table;

PL/SQL Package Body

PL/SQL Package Body : BULK_PLSQL_TABLE
create or replace package body bulk_plsql_table
as

procedure bulk_plsql_table
(
  i_plsqltab_number   in plsql_table_number, 
  i_plsqltab_date     in plsql_table_date, 
  i_plsqltab_varchar  in plsql_table_varchar
)
is
begin
  forall i in 1..i_plsqltab_number.count
    insert into bulk_processing_table
      (n,d,s)
      values
      (i_plsqltab_number(i), to_date(i_plsqltab_date(i), 'yyyy/mm/dd'), i_plsqltab_varchar(i));
end bulk_plsql_table;

end bulk_plsql_table;

Factory API : Calling the PL/SQL package

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

import java.sql.Date;
import java.text.SimpleDateFormat;
import java.util.UUID;

import factory.ExamplesRPCFactory;
import plsql_workbench_examples.timer.TimerCounter;
import service.BulkPlsqlTableService;

public class BulkCollectionPlSqlTableFactoryApi {
  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.109:1521/orcl");
      System.setProperty("dbw_examples.username", "dbw_examples");
      System.setProperty("dbw_examples.password", "dbw_examples");

      // getting the service
      BulkPlsqlTableService service = ExamplesRPCFactory.getBulkPlsqlTableService();

      // date is transmitted as varchar2 and converted in pl/sql as date type again, because only number and varchar2 types are 
      // supported thru jdbc driver
      SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd");

      // generating 50000 elements to transfer to the stored procedure 
      Integer[] numberList = new Integer[ELEMENTS];
      String[] dateList = new String[ELEMENTS];
      String[] stringList = new String[ELEMENTS];
      for (int i = 0; i < ELEMENTS; i++) {
        numberList[i] = (int) (Math.random() * Integer.MAX_VALUE);
        dateList[i] = sdf.format(new Date(System.currentTimeMillis() + (long) (Math.random() * Integer.MAX_VALUE)));
        stringList[i] = UUID.randomUUID().toString();
      }

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

      // calling the stored procedure
      service.bulkPlsqlTable(numberList, dateList, stringList);

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

      // calling the stored procedure
      service.bulkPlsqlTable(numberList, dateList, stringList);

      // print out throughput
      System.out.println(tc.perSecond("pl/sql 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 : BulkCollectionPlSqlTableSpringApi.java
package plsql_workbench_examples.springapi;

import java.sql.Date;
import java.text.SimpleDateFormat;
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.BulkPlsqlTableService;

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

  @Autowired
  private BulkPlsqlTableService bulkPlsqlTableService;

  public static void main(String[] args)
  {
    // set database credentials and configuration parameters
    System.setProperty("dbw_examples.url", "jdbc:oracle:thin:@192.168.0.109:1521/orcl");
    System.setProperty("dbw_examples.username", "dbw_examples");
    System.setProperty("dbw_examples.password", "dbw_examples");

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

  private void runDemo()
  {
    try {
      // date is transmitted as varchar2 and converted in pl/sql as date type again, because only number and varchar2 types are 
      // supported thru jdbc driver
      SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd");

      // generating 50000 elements to transfer to the stored procedure 
      Integer[] numberList = new Integer[ELEMENTS];
      String[] dateList = new String[ELEMENTS];
      String[] stringList = new String[ELEMENTS];
      for (int i = 0; i < ELEMENTS; i++) {
        numberList[i] = (int) (Math.random() * Integer.MAX_VALUE);
        dateList[i] = sdf.format(new Date(System.currentTimeMillis() + (long) (Math.random() * Integer.MAX_VALUE)));
        stringList[i] = UUID.randomUUID().toString();
      }

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

      // calling the stored procedure
      bulkPlsqlTableService.bulkPlsqlTable(numberList, dateList, stringList);

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

      // calling the stored procedure
      bulkPlsqlTableService.bulkPlsqlTable(numberList, dateList, stringList);

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