Usando canais para carregar dados no DB2 para Linux, UNIX e Windows

Aprenda como codificar para que canais usem o DB2 Load

Mover dados de um banco de dados de origem para o IBM® DB2® para Linux®, UNIX® e Windows® pode ser um desafio; especialmente quando o banco de dados de origem é relativamente grande e não há espaço suficiente para conter os arquivos de dados intermediários. O código de amostra fornecido e descrito neste artigo concede meios para utilizar um canal para carregar os dados para DB2 em ambientes do Windows e UNIX sem utilizar arquivos intermediários.

Vikram S. Khatri, Certified Consulting I/T Specialist, EMC

Vikram S Khatri trabalha na IBM na Divisão de Vendas e Distribuição e é um membro da equipe de Migração de DB2. Vikram tem 23 anos de experiência em TI e é especializado na habilitação de aplicativos não DB2 para DB2. Vikram suporta a organização de vendas técnicas de DB2 ajudando em projetos complexos de migração de bancos de dados e testes de avaliação de desempenho de bancos de dados.


nível de autor Contribuidor do
        developerWorks

Sushma Yeleshwarapu, System Software Engineer, WSO2 Inc

Sushma Yeleshwarapu trabalha no Laboratório de Software da IBM na Índia e suporta o desenvolvimento de códigos de amostra no DB2.



18/Fev/2010

Motivação

Em ambientes UNIX e Linux, pode-se criar canais nomeados usando o comando mkfifo. Pode-se, então, usar o canal com o comando LOAD do DB2. No entanto, o sistema operacional Windows não permite a criação de um canal nomeado usando um comando externo similar ao mkfifo. No Windows, é necessário criar um canal nomeado através da API do Windows e o escopo do canal é somente dentro da sessão na qual ele está criado. Também, o canal nomeado criado com Java não pode interagir com o shell do Windows e, assim, não pode ser usado pelo comando LOAD do DB2.

O arquivo pipeload.zip file, cujo link está na seção de Download deste artigo, contém códigos de amostra para ajudar a resolver esse problema. O código de amostra permite a criação de um canal do Windows que pode ser usado pelo comando LOAD do DB2. Pode-se fazer isso criando wrappers de Java Native Interface (JNI) que usem chamadas para a API do Windows através de um programa C para criar e usar canais nomeados. Pode-se, então, usar um programa Java para enviar os dados ao canal do Windows.

Visão geral do código de amostra

Em um alto nível, o código de amostra usa um programa de driver Java (TestPipe.java ou TestUnixPipe.java) para enviar dados ao canal nomeado. Então, db2load.sql consome os dados através de um canal em um shell de comando separado. O uso desse conceito é demonstrado no IBM Data Movement Tool (consulte o seção Recursos para o link de um artigo do developerWorks que descreve o IBM Data Movement Tool).

A seguir, estão as descrições dos arquivos principais contidos no arquivo de download pipeload.zip:

  • Pipe.c — Contém o código C que usa as APIs do Windows para criar, usar e fechar canais nomeados do Windows.
  • Pipes.java —Contém a Java Native Interface (JNI) que declara wrappers para todos os métodos nativos do Windows usados no Pipe.c.
  • TestPipe.java — Contém chamadas JNI para criar, usar e fechar canais nomeados do Windows.
  • TestUnixPipe.java — Contém uma chamada do sistema para o comando mkfifo para criar, usar e abandonar um canal nomeado no UNIX.
  • db2load.sql — Contém um comando LOAD do DB2 usando um canal.

Canais nomeados no Windows

Os canais nomeados criados no Windows não são permanentes como os do Unix e Linux e não se pode criá-los como um arquivo especial. Pode-se acessar um canal nomeado do Windows de maneira similar a um arquivo, mas o canal não estará visível no Windows Explorer. Os canais do Windows são montados em um sistema de arquivos especial. Pode-se usar as funções SDK do Windows, como CreateFile, ReadFile, WriteFile e CloseHandle, para abrir um canal, ler a partir dele, gravar nele e fechá-lo.


Canais nomeados no UNIX e Linux

Como UNIX ou Linux, pode-se criar um canal nomeado com o comando mkfifo ou mknod. Dois processos separados podem acessar o canal criado. O comando mkfifo cria um arquivo primeiro a entrar, primeiro a sair (FIFO). Pode-se, então, usar esse arquivo FIFO para mover informações de um aplicativo para outro sem armazenar dados em um arquivo intermediário. Assim, economiza-se espaço que, caso contrário, seria usado para armazenar arquivos temporários. O comando mknod também cria um canal nomeado se a opção p for especificada para o tipo.

A seguir, estão as amostras de comandos para desempenhar as duas etapas para a criação de um canal nomeado e carregar os dados DB2 em um ambiente Unix ou Linux.

Etapa 1 — crie um canal nomeado e envie os dados descompactados ao canal:

$ mkfifo db2pipe
$ gunzip tabledata.gz > db2pipe

Etapa 2 — use o canal para carregar os dados descompactados no DB2:

$ db2 connect to sample
$ db2 "LOAD FROM db2pipe OF DEL INSERT INTO mytable"
$ db2 terminate

JNI para acessar métodos nativos do Windows

O código programa Pipes.java declara os métodos Java que apontam de volta para as chamadas de API nativas do Windows implementadas através do programa Pipe.c. É necessário executar Pipes.java através do programa javah para criar um arquivo de cabeçalho que possua especificações para que o programa C possa corresponder à assinatura dos métodos C.

Observe que está fora do escopo deste artigo fornecer uma descrição completa da JNI.

Listagem 1. Declarações de métodos JNI no arquivo Pipes.java
public class Pipes
{
   static
   {
      System.loadLibrary("Pipe");
   }

   public static final native int CreateNamedPipe(String pipeName,
      int ppenMode, int pipeMode, int maxInstances,
   int outBufferSize, int inBufferSize, int defaultTimeOut,
      int securityAttributes);

   public static final native boolean ConnectNamedPipe(int namedPipeHandle, 
      int overlapped);
   public static final native int GetLastError();
   public static final native boolean CloseHandle(int bbject);
   public static final native byte[] ReadFile(int file, int numberOfBytesToRead);
   public static final native int WriteFile(int file, byte[] buffer, 
      int numberOfBytesToWrite);
   public static final native boolean FlushFileBuffers(int file);
   public static final native boolean DisconnectNamedPipe(int namedPipeHandle);
   public static final native int CreateFile(String fileName,
      int desiredAccess, int shareMode, int securityAttributes,
      int creationDisposition, int flagsAndAttributes,
      int templateFile);

   public static final native boolean WaitNamedPipe(String namedPipeName, int timeOut);
   public static final native String FormatMessage(int errorCode);
   public static final native void Print(String message);
}

Crie um arquivo de cabeçalho JNI

Use o código a seguir para compilar e criar um arquivo de cabeçalho JNI para Pipes.java:

javac ibm/Pipes.java
javah -jni ibm.Pipes

Copie o arquivo ibm_Pipes.h do código de amostra para a pasta do seu programa C.


Código C para envolver métodos do Windows

O código C de amostra na Listagem 2 é do arquivo Pipe.c no download de amostra. O código cria funções C que correspondem às declarações no arquivo de cabeçalho criado usando o programa javah na etapa anterior.

Listagem 2. Código de amostra listando para o código JNI
#include <windows.h> 
#include <strsafe.h>
#include <jni.h>
#include "ibm_Pipes.h"

#define  DEBUG 0

JNIEXPORT jint JNICALL Java_ibm_Pipes_CreateNamedPipe
(
    JNIEnv *env, 
    jclass className, 
    jstring sPipeName, 
    jint dwOpenMode, 
    jint dwPipeMode, 
    jint nMaxInstances, 
    jint nOutBufferSize, 
    jint nInBufferSize, 
    jint nDefaultTimeOut, 
    jint lpSecurityAttributes
 )
{
   HANDLE pipeHandler;
   LPCSTR pipeName;
   pipeName = (*env)->GetStringUTFChars(env, sPipeName, NULL);
   if (pipeName == NULL)
      return -1;

   if (DEBUG)
   {
      printf("Native: Pipe Name %s\n", pipeName);
      printf("Native: dwOpenMode %d\n", dwOpenMode);
      printf("Native: dwPipeMode %d\n", dwPipeMode);
      printf("Native: nMaxInstances %d\n", nMaxInstances);
      printf("Native: nOutBufferSize %d\n", nOutBufferSize);
      printf("Native: nInBufferSize %d\n", nInBufferSize);
      printf("Native: nDefaultTimeOut %d\n", nDefaultTimeOut);
   }

   pipeHandler = CreateNamedPipe((LPCSTR)pipeName, dwOpenMode, 
                     dwPipeMode, nMaxInstances, nOutBufferSize, 
                     nInBufferSize, nDefaultTimeOut, 
                   (LPSECURITY_ATTRIBUTES) lpSecurityAttributes);  

   (*env)->ReleaseStringUTFChars(env, sPipeName, pipeName);
   return (jint) pipeHandler;
}

JNIEXPORT jboolean JNICALL Java_ibm_Pipes_ConnectNamedPipe
(
    JNIEnv *env, 
    jclass className, 
    jint hNamedPipe, 
    jint lpOverlapped
 )
{
   BOOL fConnected;
   HANDLE pipeHandler = (HANDLE) hNamedPipe;
   fConnected = ConnectNamedPipe(pipeHandler, 
                           (LPOVERLAPPED) lpOverlapped);
   return fConnected;
}

JNIEXPORT jint JNICALL Java_ibm_Pipes_GetLastError 
(
    JNIEnv *env, 
    jclass className
 )
{
   DWORD errorNumber = GetLastError();
   return (jint) errorNumber;
}

JNIEXPORT jboolean JNICALL Java_ibm_Pipes_CloseHandle
(
    JNIEnv *env, 
    jclass className, 
    jint hNamedPipe
 )
{
   BOOL result;
    HANDLE pipeHandler = (HANDLE) hNamedPipe;
   result = CloseHandle(pipeHandler);
   return result;
}

JNIEXPORT jbyteArray JNICALL Java_ibm_Pipes_ReadFile
(
    JNIEnv *env, 
    jclass className, 
    jint hNamedPipe, 
    jint nNumberOfBytesToRead
 )
{
   int bytesRead = 0;
   BOOL result;
    HANDLE pipeHandler = (HANDLE) hNamedPipe;
   LPVOID buffer;
   jbyteArray lpBuffer;

   buffer = (LPVOID)LocalAlloc(LMEM_ZEROINIT, nNumberOfBytesToRead);

   if (DEBUG)
   {
      printf("Native: Before ReadFile pipeHandler %d 
         nNumberOfBytesToRead %d\n", pipeHandler, nNumberOfBytesToRead);
   }
   result = ReadFile(pipeHandler, (LPVOID) buffer, 
                     (DWORD) nNumberOfBytesToRead, 
                     &bytesRead, (LPOVERLAPPED) 0);
   if (result)
   {
      lpBuffer = (*env)->NewByteArray(env, (jsize) bytesRead);    
      (*env)->SetByteArrayRegion(env, lpBuffer, 0, 
                             (jsize) bytesRead, (jbyte *) buffer);
   } else
      bytesRead = 0;

   LocalFree(buffer);

   if (DEBUG)
   {
      printf("Native: After ReadFile BytesRead %d\n", bytesRead);
   }
   return lpBuffer;
}

JNIEXPORT jint JNICALL Java_ibm_Pipes_WriteFile
(
    JNIEnv *env, 
    jclass className, 
    jint hNamedPipe, 
    jbyteArray lpBuffer, 
    jint nNumberOfBytesToWrite
 )
{
   int bytesWritten = 0;
   BOOL result;
    HANDLE pipeHandler = (HANDLE) hNamedPipe;
   LPVOID buffer;

   buffer = (LPVOID)LocalAlloc(LMEM_ZEROINIT, nNumberOfBytesToWrite);

   (*env)->GetByteArrayRegion(env, lpBuffer, 0, 
                    nNumberOfBytesToWrite, buffer);
   result = WriteFile(pipeHandler, buffer, 
                      (DWORD) nNumberOfBytesToWrite, 
                      (LPDWORD) &bytesWritten, (LPOVERLAPPED) 0);
   LocalFree(buffer);

   if (DEBUG)
   {
      printf("Native: After WriteFile BytesReadWritten %d\n", 
             bytesWritten);
   }

   if (!result)
   {
      if (GetLastError() != ERROR_IO_PENDING)
         result = 0;
      else
         result = 1;
   }
   if (!result)
   {
      bytesWritten = -1;
   }
   return bytesWritten;
}

JNIEXPORT jboolean JNICALL Java_ibm_Pipes_FlushFileBuffers
(
    JNIEnv *env, 
    jclass className, 
    jint hNamedPipe
 )
{
   BOOL result;
    HANDLE pipeHandler = (HANDLE) hNamedPipe;
   result = FlushFileBuffers(pipeHandler); 
   return result;
}

JNIEXPORT jboolean JNICALL Java_ibm_Pipes_DisconnectNamedPipe
(
    JNIEnv *env, 
    jclass className, 
    jint hNamedPipe
 )
{
   BOOL result;
    HANDLE pipeHandler = (HANDLE) hNamedPipe;
   result = DisconnectNamedPipe(pipeHandler);
   return result;
}

JNIEXPORT jint JNICALL Java_ibm_Pipes_CreateFile
(
    JNIEnv *env, 
    jclass className, 
    jstring lpFileName, 
    jint dwDesiredAccess, 
    jint dwShareMode, 
    jint lpSecurityAttributes, 
    jint dwCreationDisposition, 
    jint dwFlagsAndAttributes, 
    jint hTemplateFile
 )
{
    HANDLE pipeHandler;
   const jbyte *fileName;
   fileName = (*env)->GetStringUTFChars(env, lpFileName, NULL);
   if (fileName == NULL)
      return -1;
   pipeHandler = CreateFile((LPCSTR) fileName, 
                            (DWORD) dwDesiredAccess, (DWORD) dwShareMode, 
      (LPSECURITY_ATTRIBUTES) lpSecurityAttributes, 
                            (DWORD) dwCreationDisposition, 
                            (DWORD) dwFlagsAndAttributes, 
                            (HANDLE) hTemplateFile);
   return (jint) pipeHandler;
}

JNIEXPORT jboolean JNICALL Java_ibm_Pipes_WaitNamedPipe
(
    JNIEnv *env, 
    jclass className, 
    jstring lpNamedPipeName, 
    jint nTimeOut
 )
{
   BOOL result;
   const jbyte *pipeName;
   pipeName = (*env)->GetStringUTFChars(env, lpNamedPipeName, NULL);
   if (pipeName == NULL)
      return 0;
   result = WaitNamedPipe((LPCSTR) pipeName, (DWORD) nTimeOut);
   return result;
}

JNIEXPORT jstring JNICALL Java_ibm_Pipes_FormatMessage
(
   JNIEnv *env, 
   jclass className, 
   jint errorCode
)
{
   LPVOID lpMsgBuf;
    LPVOID lpDisplayBuf;
   DWORD dw = (DWORD) errorCode;

   FormatMessage(
        FORMAT_MESSAGE_ALLOCATE_BUFFER | 
        FORMAT_MESSAGE_FROM_SYSTEM |
        FORMAT_MESSAGE_IGNORE_INSERTS,
        NULL,
        dw,
        MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
        (LPTSTR) &lpMsgBuf,
        0, NULL );

   lpDisplayBuf = (LPVOID)LocalAlloc(LMEM_ZEROINIT, 
        (lstrlen((LPCTSTR)lpMsgBuf) + 40) * sizeof(TCHAR)); 
    StringCchPrintf((LPTSTR)lpDisplayBuf, 
                    LocalSize(lpDisplayBuf) / sizeof(TCHAR),
        TEXT("Failed with error %d: %s"), dw, lpMsgBuf); 
   return (jstring) (*env)->NewStringUTF(env, lpDisplayBuf);
}

JNIEXPORT void JNICALL Java_ibm_Pipes_Print(JNIEnv *env, 
                                            jclass className, 
                                            jstring lpMsgBuf)
{  
   const jbyte *str;
   str = (*env)->GetStringUTFChars(env, lpMsgBuf, NULL);
   if (str == NULL)
      return;
   printf("Native: %s\n", str);
   (*env)->ReleaseStringUTFChars(env, lpMsgBuf, str);
   return;
}

Compile o programa C no Windows

Para compilar e criar uma biblioteca de links dinâmicos (DLL), é necessário o compilador cl.exe do Windows. Caso ainda não possua o cl.exe, pode-se obtê-lo fazendo o download do Microsoft Visual Studio Express Edition. Está fora do escopo deste artigo fornecer instruções de como usar o Visual Studio para compilar um programa C. No entanto, pode-se simplesmente usar cl.exe da linha de comando para criar a DLL, com é mostrado a seguir:

cl -I"C:\Program Files\IBM\Java50\include" -I"C:\Program Files\IBM\Java50\include\win32" 
       -LD Pipe.c -FePipe.dll

Ao usar cl.exe para criar uma DLL, lembre-se de copiar o arquivo ibm_Pipes.h do diretório atual e substituir as referências para o diretório de inclusão Java com o local real do diretório em seu sistema.


Programa Java de amostra para usar os canais do Windows

Use o código na Listagem 3 para criar um canal nomeado no Windows usando os métodos nativos declarados no cabeçalho do arquivo Pipes.h e implementados no código Pipe.c.

Listagem 3. Programa TestPipe.java de amostra para usar um canal do Windows
package ibm;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;

public class TestPipe
{
   static final int ERROR_PIPE_CONNECTED = 535;
   static final int ERROR_BROKEN_PIPE = 109;
   private int namedPipeHandle;
   private String pipeName, srcFile;
   private int pipeBuffer = 131072, fileBuffer = 8192;
   
   public TestPipe(String pipeName, String srcFile)
   {
      this.pipeName = pipeName;
      this.srcFile = srcFile;    
   }
   
   private void log(String message)
   {
      System.out.println(message);     
   }  

   private boolean createPipe()
   {
      boolean ok = false;
      namedPipeHandle = Pipes.CreateNamedPipe(pipeName, 
                0x00000003, 0x00000000, 2, pipeBuffer, 
                pipeBuffer, 0xffffffff, 0);
      if (namedPipeHandle == -1)
      {
         log("CreateNamedPipe failed for " + pipeName + 
               " for error " + " Message " + 
                    Pipes.FormatMessage(Pipes.GetLastError()));
         ok = false;
      } else
      {
         log("Named Pipe " + pipeName + 
              " created successfully Handle=" + namedPipeHandle);
         ok = true;
      }
      return ok;
   }
   
   private boolean connectToPipe()
   {
      log("Waiting for a client to connect to pipe " + pipeName);
      boolean connected = Pipes.ConnectNamedPipe(namedPipeHandle, 0);
      if (!connected)
      {
         int lastError = Pipes.GetLastError();
         if (lastError == ERROR_PIPE_CONNECTED)
            connected = true;
      }
      if (connected)
      {
         log("Connected to the pipe " + pipeName);
      } else
      {
         log("Falied to connect to the pipe " + pipeName);
      }
      return connected;
   }

   public void runPipe()
   {
      if (createPipe())
      {
         if (!connectToPipe())
         {
            log("Connect ConnectNamedPipe failed : " + 
                  Pipes.FormatMessage(Pipes.GetLastError()));
            return;
         } else
         {
            log("Client connected.");
         }
         
         try
         {
            File f1 = new File(this.srcFile);
            InputStream in = new FileInputStream(f1);
            log("Sending data to the pipe");
            byte[] buf = new byte[fileBuffer];
            int len, bytesWritten;
            while ((len = in.read(buf)) > 0)
            {
              bytesWritten = Pipes.WriteFile(namedPipeHandle, buf, len);
              log("Sent " + len + "/" + bytesWritten + 
                               " bytes to the pipe");
              if (bytesWritten == -1)
              {
                 int errorNumber = Pipes.GetLastError();
                 log("Error Writing to pipe " + 
                            Pipes.FormatMessage(errorNumber));
              }                  
            }
            in.close();
            Pipes.FlushFileBuffers(namedPipeHandle);
            Pipes.CloseHandle(namedPipeHandle);
            Pipes.DisconnectNamedPipe(namedPipeHandle);
            log("Writing to the pipe completed.");
         } catch (Exception e)
         {
            e.printStackTrace();
         }
      }     
   }
   
   public static void main(String[] args) throws IOException, 
               InterruptedException 
   {
      String pipeName = "\\\\.\\pipe\\mynamedpipe";
      String fileName = "C:\\db2tabledata.txt";;
      TestPipe testPipe = new TestPipe(pipeName, fileName);
      testPipe.runPipe();
   }
}

Programa Java de amostra para usar canais do UNIX

No UNIX, não é necessário que o código Java invoque um programa C e crie um canal nomeado. Isso é devido ao fato de o UNIX poder criar um canal nomeado usando diretamente um comando mkfifo ou mknod. O código na Listagem 4 mostra um exemplo de uso de um canal nomeado no UNIX.

Listagem 4. Programa TestUnixPipe.java de amostra para usar um canal UNIX nomeado
package ibm;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;

public class TestUnixPipe
{
   FileChannel fc;
   int multiTables[] = new int[1];
   String filesep = System.getProperty("file.separator");
   String fileName, OUTPUT_DIR = ".", pipeName;
   int pipeBuffer = 131072, fileBuffer = 8192;
   
   public TestUnixPipe(String fileName, String output)
   {
      this.fileName = fileName;
      this.OUTPUT_DIR = output;
      multiTables[0] = 0;
   }
   
   private void log(String message)
   {
      System.out.println(message);     
   }
   
   public void runPipe()
   {
      int bytesReturn;
      pipeName = OUTPUT_DIR + "data" + filesep + pipeName + ".pipe";
      File pipeFile = new File(pipeName);
      pipeFile.deleteOnExit();
      if (!pipeFile.exists())
      {
         try
         {
            Runtime.getRuntime().exec("mkfifo " + 
                pipeFile.getAbsolutePath());
         } catch (Exception e)
         {
            e.printStackTrace();
         }
      }
      FileOutputStream fos = null;
      try
      {
         if (multiTables[0] == 0)
         {
            fos = new FileOutputStream(pipeFile);
            fc = fos.getChannel();                       
         } else
         {
            fc = fc;
         }
      } catch (Exception e)
      {
         e.printStackTrace();
      }
      try
      {
         File f1 = new File(this.fileName);
         InputStream in = new FileInputStream(f1);
         log("Sending data to the pipe");
         byte[] buf = new byte[fileBuffer];
          int len;
          while ((len = in.read(buf)) > 0)
          {
            bytesReturn = fc.write(ByteBuffer.wrap(buf));            
            log("Sent " + len + "/" + bytesReturn + 
                    " bytes to the pipe");
            if (bytesReturn == -1)
            {
               log("Error Writing to pipe " + pipeName);
            }                  
          }
          in.close();
         log("Writing to the pipe completed.");
      } catch (Exception e)
      {
         e.printStackTrace();
      }
   }
   
   public static void main(String[] args) throws IOException, 
             InterruptedException 
   {
      String output = ".";
      String fileName = "/home/db2inst1/db2tabledata.txt";;
      TestUnixPipe testPipe = new TestUnixPipe(fileName, output);
      testPipe.runPipe();
   }
}

Execute o programa TestPipe.java para usar um canal do Windows

Use os seguintes comandos para compilar e executar o programa TestPipe.java de amostra (Listagem 3).

javac TestPipe.java
java -Djava.library.path=".." ibm.TestPipe

No exemplo acima, passe a propriedade de sistema java.library.path ao JVM para indicar o local onde o JVM pode procurar pelo Pipe.dll para invocar métodos nativos do Windows. No exemplo, o Pipe.dll está localizado um nível acima do diretório atual.

Ao executar TestPipe, ele cria um canal nomeado chamado \\.\pipe\mynamedpipe e se conecta ao canal. Ele, então, espera por um outro programa (neste caso, o comando LOAD do DB2) para se conectar a ele antes de iniciar a gravação de dados no canal. Quando o LOAD do DB2 se conectar ao canal, o programa Java começa a enviar os conteúdos do arquivo db2tabledata.txt ao canal e o LOAD do DB2 consome esses dados.

Figura 1. Executando o código Java de amostra a partir do prompt de comandos do Windows
Windows command prompt. Command to run Java sample code issued. Messages show that the pipe is created and program is waiting.

Script DB2 Load para usar o canal para uma tabela

Como descrito na seção anterior, depois que o programa TestPipe se conecta ao canal, ele espera um outro programa se conectar a ele. Para fazer essa outra conexão, execute o script DB2 db2load.sql de amostra (Listagem 5). Isso cria uma tabela e inicia o LOAD do mynamedpipe.

Listagem 5. Script DB2 de exemplo para criar uma tabela e iniciar o LOAD
CONNECT TO SAMPLE;

CREATE TABLE PIPE_TABLE
(
"ID" NUMBER(10)  NOT NULL ,
"NAME" VARCHAR2(35)  ,
"LOC_ID" NUMBER(4)  
)
;
 
LOAD  FROM 
"\\.\pipe\mynamedpipe"
OF DEL 
MODIFIED BY CODEPAGE=1208  COLDEL~ ANYORDER  
   USEDEFAULTS CHARDEL"" DELPRIORITYCHAR  NOROWWARNINGS 
METHOD P (1,2,3)
MESSAGES "db2tabledata.txt"
REPLACE INTO PIPE_TABLE
(
"ID",
"NAME",
"LOC_ID"
)
 NONRECOVERABLE 
INDEXING MODE AUTOSELECT
;

TERMINATE;

Para invocar o script db2load.sql, abra o processador de linha de comando (CLP) do DB2 e execute o seguinte comando:

db2 -tf db2load.sql

A Figura 2 representa o processamento simultâneo que ocorre entre o script db2load.sql e o programa TestPipe.java. Observe que assim que o comando LOAD do DB2 se conecta ao canal nomeado do Windows, o programa Java começa a gravar dados no canal. De maneira simultânea, o LOAD do DB2 consome esses dados e os carrega no DB2.

Figura 2. Janela do CLP do DB2 executando db2load.sql e o prompt de comandos do Windows executando o TestPipe.java executando o TestPipe
After db2load.sql makes connection to the pipe, TestPipe writes the test data to the pipe and it is loaded into DB2.

Execute o programa TestUnixPipe.java para usar o canal UNIX

Pode-se executar o programa TestUnixPipe.java em sistemas UNIX e observar o mesmo tipo de comportamento descrito acima para o ambiente Windows. A exceção é, claro, que se poderia usar o recurso do UNIX para criar diretamente o canal.


Usando canais com o IBM Data Movement Tool

Pode-se customizar e usar os códigos de amostra deste artigo se você possuir seus próprios requisitos para processar dados através de programas Java ou C/C++ e sua motivação principal é evitar ter que usar arquivos de dados intermediários. No entanto, se sua motivação for simplesmente descarregar dados de um banco de dados de origem e carregá-los no DB2 usando canais, pode-se simplesmente usar o IBM Data Movement Tool com a opção Use Pipe, como mostra a Figura 3.

Com o IBM Data Movement Tool, primeiro extraia e crie definições de tabela de um banco de dados de origem para o DB2 e, então, use a opção de canal para carregar os dados. Pode-se fazer isso em paralelo ao descarregamento. Pode-se carregar e descarregar dados de tabelas únicas ou múltiplas em paralelo. Para mais informações sobre a ferramenta e como usá-la, consulte o link do artigo sobre o IBM Data Movement na seção Recursos.

Figura 3. Captura de tela do IBM Data Movement Tool
The screenshot highlights that the Use Pipe option is checked.

Conclusão

O utilitário LOAD do DB2 é muito eficiente e permite explorar ao máximo o hardware do servidor para carregar dados. No entanto, em um ambiente com bancos de dados grandes, o espaço para conter os dados intermediários pode se tornar um problema. Pode-se superar esse problema usando o recurso dos canais. O uso de canais em plataformas é o mesmo do uso de um arquivo normal, exceto pelo fato de no ambiente Windows, há etapas extras para criar os canais e o programa Java deve usar JNI para acessar a API do Windows. A introdução deste artigo com o código de amostra incluído no arquivo de download deve aliviar um pouco da complexidade desse processo e facilitar a realização desse tipo de tarefa.


Download

DescriçãoNomeTamanho
Sample Java and C code for this articlepipeload.zip28KB

Recursos

Aprender

Obter produtos e tecnologias

Discutir

Comentários

developerWorks: Conecte-se

Los campos obligatorios están marcados con un asterisco (*).


Precisa de um ID IBM?
Esqueceu seu ID IBM?


Esqueceu sua senha?
Alterar sua senha

Ao clicar em Enviar, você concorda com os termos e condições do developerWorks.

 


A primeira vez que você entrar no developerWorks, um perfil é criado para você. Informações no seu perfil (seu nome, país / região, e nome da empresa) é apresentado ao público e vai acompanhar qualquer conteúdo que você postar, a menos que você opte por esconder o nome da empresa. Você pode atualizar sua conta IBM a qualquer momento.

Todas as informações enviadas são seguras.

Elija su nombre para mostrar



Ao se conectar ao developerWorks pela primeira vez, é criado um perfil para você e é necessário selecionar um nome de exibição. O nome de exibição acompanhará o conteúdo que você postar no developerWorks.

Escolha um nome de exibição de 3 - 31 caracteres. Seu nome de exibição deve ser exclusivo na comunidade do developerWorks e não deve ser o seu endereço de email por motivo de privacidade.

Los campos obligatorios están marcados con un asterisco (*).

(Escolha um nome de exibição de 3 - 31 caracteres.)

Ao clicar em Enviar, você concorda com os termos e condições do developerWorks.

 


Todas as informações enviadas são seguras.


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=80
Zone=Information Management
ArticleID=475507
ArticleTitle=Usando canais para carregar dados no DB2 para Linux, UNIX e Windows
publish-date=02182010