Создание высокопроизводительных Java-приложений для доступа к данным: Часть 2. Введение в программирование pureQuery

Рационализация общих задач с целью достижения простоты и удобства работы пользователя

IBM® pureQuery – это высокопроизводительная Java™-платформа для доступа к данным, ориентированная на упрощение разработки приложений, которые обращаются к данным, и управления ими. Она состоит из инструментальных средств, интерфейсов прикладных программ (API) и среды исполнения. pureQuery предлагает два стиля программирования, которые помогают пользователям обращаться к базам данных посредством простых, но мощных API. В этой статье описан один из этих стилей, стиль программирования на основе встроенных методов, и объясняется, как его применять для эффективного обращения к базам данных и их редактирования. Также разъясняются преимущества и некоторые ключевые особенности применения стиля программирования на основе встроенных методов.

Введение

pureQuery

Инструментарий pureQuery входит в состав IBM Data Studio, и его можно получить вместе с IBM Data Studio pureQuery Runtime или IBM Data Studio Developer.

pureQuery предлагает два новых стиля программирования для исполнения SQL: на основе встроенных методов и на основе аннотированных методов. Эти стили упрощают разработку Java-приложений для доступа к данным, обеспечивая готовую поддержку для сохранения и извлечения объектов, таких как Java-компоненты и таблицы, в базу данных и из нее. Стиль программирования на основе встроенных методов поддерживает также применение настраиваемых определяемых пользователем процессов обработки результатов.

Стиль на основе аннотированных методов обеспечивает доступ к данным, основанный на аннотациях. При этом стиле строка SQL/XQUERY определяется внутри pureQuery Annotation. Эти аннотации размещаются в декларациях методов внутри пользовательского интерфейса. Генератор кода предварительно обрабатывает интерфейс, генерируя код реализации для каждого аннотированного метода. Сгенерированный код реализации исполняет операторы SQL, определенные в аннотации, при помощи среды исполнения pureQuery. Подробнее о стиле программирования на основе аннотированных методов можно прочесть в первой части этой серии или в документации по pureQuery.

Стиль программирования на основе встроенных методов pureQuery был предложен для уменьшения числа повторяющихся задач, характерных для считывания данных или редактирования базы данных с применением JDBC. Стиль программирования на основе встроенных методов предлагает ряд хорошо определенных и эффективных API, применять которые проще и легче, чем JDBC. При этом подходе операторы SQL/XQUERY могут создаваться внутри кода (inline) как объекты String Java. Такой динамически генерируемый оператор передается в качестве параметра String в метод интерфейса pureQuery Data. Для повышения производительности стиль на основе встроенных методов использует лучшие приемы JDBC и API, оптимизированные для конкретной базы данных. Примером стиля программирования на основе встроенных методов служит пакетное редактирование и оптимизированная обработка результатов. В отличие от стиля на основе аннотированных методов, где операторы SQL должны быть определены на стадии компиляции, стиль на основе встроенных методов поддерживает динамическое создание и исполнение операторов SQL во время прогона. Код SQL «встроен» и виден внутри приложения, и это упрощает выявление ошибок и внесение поправок. Стиль на основе встроенных методов предусматривает также возможность включения специализированной обработки результатов для упрощения отображения столбцов базы данных.

В таблице 1 приведен фрагмент кода для демонстрации простоты и удобства использования стиля программирования на основе встроенных методов.

Таблица 1. Сопоставление кода JDBC и стиля программирования на основе встроенных методов pureQuery
JDBCСтиль на основе встроенных методов pureQuery
try  {



  //SQL for insert
  String sqlins="'insert into CUSTOMER ("
  +    "NAME, COUNTRY, STREET, CITY, PROVINCE, ZIP,"
  +    "PHONE,INFO)"
  +    "values( ?, ?, ?, ?, ?, ?, ?, ?)";



  //prepare the INSERT statement
  PreparedStatement pstmt = 
       con.prepareStatement(sqlins );

  // setup parameters
  pstmt.setString (1, "custName");
  pstmt.setString (2, "custCountry");
  pstmt.setString (3, "custStreet");
  pstmt.setString (4, "custCity");
  pstmt.setString (5, "custProvince");
  pstmt.setString (6, "custZip");
  pstmt.setString (7, "custPhone");
  pstmt.setString (8, "custInfo");

  
  //execute the INSERT statement
  pstmt.execute();



  //close the prepared statement
  pstmt.close();

  // SQL for SELECT
  String sqlSel = "select Name, Country, Street, "
  + "Province,Zip from CUSTOMER where Customer = ?"; 

  //prepare the SELECT statement 
  pstmt =  con.prepareStatement(sqlSel);
  
  //set the Input parameter
  pstmt.setString (1, "custCountry");

  //execute SELECT statement
  pstmt.execute();



  //get the results and set values in Customer Bean
  ResultSet result = pstmt.getResultSet ();
  List<Customer> custList = 
  new ArrayList<Customer>();
  while (result.next ()) {
  Customer cust = new Customer();
  cust.name = result.getString (1);
  cust.country = result.getString (2);
  cust.street = result.getString (3);
  cust.province = result.getString (4);
  cust.zip = result.getString (5);
  custList.add (cust);
   }
}
catch (SQLException e) {
  e.pringStackTrace ();
}
//Get Instance of Data  
Data data = DataFactory.getData(con);

// SQL for insert  
String sqlins = "insert into CUSTOMER (" 
+     "NAME,COUNTRY,STREET,CITY,PROVINCE,ZIP, "
+     "PHONE, INFO)" 
+    "values( ?, ?, ?, ?, ?, ?, ?, ?)";


















//execute the INSERT statement
data.update (sqlins, "custName", 
"custCountry", "custStreet", "custCity", 
"custProvince", "custZip", "custPhone", "custInfo");




// SQL for SELECT
String sqlSel = "select Name, Country, Street, " 
+ "Province,Zip from CUSTOMER where Customer = ?"; 







//execute the Select and get the list of customer
List<Customer> customerList = data.queryList (sqlSel, Customer.
class , "custCountry");











Настоящая статья содержит:

  • описание различных элементов кода, необходимых при использовании стиля программирования на основе встроенных методов;
  • практический пример, иллюстрирующий особенности стиля программирования на основе встроенных методов;
  • описание возможных запросов при использовании стиля программирования на основе встроенных методов, включая поддержку отображения по умолчанию pureQuery и поддержку специальных отображений запросов;
  • описание поддержки отдельных изменений и пакетных изменений, а также API для извлечения автоматически сгенерированных значений;
  • знакомство с подключаемым механизмом обратного вызова pureQuery.

Разработка встроенных методов

Ниже описываются некоторые объекты и API, которые могут понадобиться для программирования приложений в стиле встроенных методов.

  1. Интерфейс Data

    Интерфейс com.ibm.pdq.runtime.Data определяет удобные API для выполнения операций с базой данных. В стиле программирования на основе встроенных методов можно применять методы, определенные в интерфейсе Data, и в процессе применения метода передавать оператор SQL как параметр. Интерфейс Data содержит методы для запросов, исполнения операторов SQL CALL и возврата выходных значений. Он содержит также средства доступа к динамическим наборам результатов, созданных хранимой процедурой, и исполнения операторов языка SQL data manipulation language (DML), таких как update, insert или delete, в виде отдельной операции или в составе однородных пакетов. Многие методы запросов интерфейса Data являются групповыми и могут возвращать объекты разного типа, включая коллекции.

  2. Класс DataFactory

    Класс com.ibm.pdq.runtime.factory.DataFactory обеспечивает средства для составления реализаций интерфейса Data. Один из способов создания реализации интерфейса Data состоит в передаче объекта Connection методу DataFactory.getData().

  3. Компонент pureQuery

    Компонент pureQuery может применяться для отображения реляционных данных в виде таблиц базы данных, представлений, наборов результатов и т.п. Хотя методы API pureQuery могут работать со входными параметрами и возвращать значения, определенные как неструктурированные типы, использование компонента pureQuery предоставляет программисту лучшие возможности по отображению реляционных данных на объекты Java. pureQuery анализирует объявленные свойства, методы и аннотации компонента и определяет, как установить соответствие между свойствами компонента и свойствами ввода-вывода оператора SQL. Более подробные сведения о соглашениях и требованиях для компонентов pureQuery содержатся в документации по pureQuery.

  4. Java-приложение со встроенными методами

    Это файл Java, в котором пользователь может создавать реализацию интерфейса Data и вызывать разные операции считывания, записи или методы запросов.


Пример Silver Castle

В этом разделе приводится пример разработки приложения с использованием pureQuery группой программистов из вымышленной компании Silver Castle. Приведенная ниже исходная информация служит для иллюстрации этой статьи наглядными примерами по каждой встроенной функции pureQuery.


Исходная информация для примера Silver Castle

Silver Castle - это растущая компания, которая продает различные изделия из серебра. Компания разрабатывает новую Web-витрину и решила использовать среду pureQuery в качестве инструмента разработки уровня персистенции для своего приложения. Когда группа программистов как следует разобралась в инструментальной среде pureQuery, они начали углубляться в технические аспекты стиля программирования на основе встроенных методов.


Пример программы в стиле встроенных методов

Группа программистов Silver Castle определила следующую таблицу Customer (листинг 1).

Листинг 1. Таблица Customer, определенная в базе данных
CREATE TABLE PDQ_SC.customer(
  Cid     INTEGER NOT NULL GENERATED ALWAYS AS IDENTITY (STARRT WITH 100, INCREMENT BY 1),
  Name       VARCHAR(128),
  Country    VARCHAR(128),
  Street     VARCHAR(128),
  City       VARCHAR(128),
  Province   VARCHAR(128),
  Zip        VARCHAR(128),
  Phone      VARCHAR(128),
  Info       VARCHAR(128),
  CONSTRAINT CID_PK primary key(Cid));

Компонент pureQuery для этой таблицы Customer можно сгенерировать при помощи инструментария Data Studio . Компонент Customer определен следующим образом (листинг 2).

Листинг 2. Класс Customer
public class Customer {
// Class variables  
 @Id
 @GeneratedKey 
 public int cid;
 public String name;
 public String country;
 public String street;
 public String city;
 public String province;
 public String zip;
 public String phone;
 public String info;

 public Customer(){}

 public Customer(String name, String country, String street, String city, String province,
                 String zip, String phone, String info){
   this.name = name;
   this.country = country;
   this.street = street;
   this.city = city;
   this.province = province;
   this.zip = zip;
   this.phone = phone;
   this.info = info;
 }
}

Теперь группа программистов Silver Castle пытается создать пробную программу (листинг 3), которая выполняет следующие операции:

  • устанавливает соединение с базой данных;
  • получает экземпляр реализации интерфейса Data;
  • удаляет все строки базы данных;
  • вставляет строку с использованием компонента pureQuery в качестве входного параметра;
  • обращается к базе данных и извлекает строки в итератор компонентов pureQuery.
Листинг 3. Манипулирование объектами данных с применением стиля встроенных методов
package com.ibm.db2.demo;

import java.sql.Connection;
import java.sql.DriverManager;
import java.util.Iterator;
import java.util.List;
import com.ibm.db2.pureQuery.Customer;
import com.ibm.pdq.runtime.Data;
import com.ibm.pdq.runtime.factory.DataFactory;

public class InlineTest
{
  
  public static void main(String args[]) {
    Connection con = null;
    String sql = null;
    String insertSql = null;
    try {
      // connection to the database
      con = DriverManager.getConnection ();

  // Get an instance to the implementation of a Data interface
      Data data = DataFactory.getData (con);
      
      //delete all rows from the table
      data.update ("delete from PDQ_SC.customer");

      //Insert using a pureQuery Bean 
      insertSql = "INSERT INTO PDQ_SC.customer (Name, Country, Street, City, " +
		   "Province, Zip, Phone)" +
                  "VALUES(:name,:country,:street,:city,:province,:zip,:phone)";
      Customer addCustomer = new Customer("Customer2","US","BlackBerry Street",
                     "San Jose","Santa Clara","82652","408-273-4856",null); 
      int insertCount = data.update (insertSql,addCustomer );
      System.out.println ("Rows Inserted " + insertCount );
      
    
      sql = "select * from  PDQ_SC.Customer where Country = ?";

      //Query with Iterator using default handler 
      Iterator<Customer> iterator = data.queryIterator (sql, Customer.class, "US");
         
      con.close ();
    }
    catch (Exception e) {
      System.out.println ("Error encountered");
      e.printStackTrace ();
    }
  }
  
  
 public static Connection getConnection ()
  {
    Connection connection = null;

    try {
      Class.forName ("com.ibm.db2.jcc.DB2Driver").newInstance ();
      java.util.Properties info = new java.util.Properties ();      
      info.put ("retrieveMessagesFromServerOnGetMessage", "true");
      info.put ("user", "USER");
      info.put ("password", "PASSWORD");
      String url = "jdbc:db2://atom.blue.test.com:298/SAMPLE:deferPrepares=false;";
      connection = DriverManager.getConnection (url, info);
    }
    catch (Exception e) {
      e.printStackTrace ();
    }

    return connection;
  }
}

Создание экземпляра объекта Data

Для создания экземпляра com.ibm.pdq.runtime.Data требуется соединение с базой данных в форме объекта java.sql.Connection или объекта javax.sql.DataSource. Когда соединение установлено, пользователь может обращаться к методу getData() в com.ibm.pdq.runtime.factory.DataFactory для создания экземпляра интерфейса Data. Кроме методов исполнения оператора SQL, интерфейс Data поддерживает методы JDBC close(), commit(), rollback() и setAutoCommit() JDBC.

Для создания соединения с базой данных группа программистов Silver Castle использует метод getConnection() (см. листинг 3). Этот метод создает соединение с применением Driver Manager API, передавая соединение с базой данных URL String. Затем соединение передается методу DataFactory.getData() для получения экземпляра интерфейса Data.


Варианты входных параметров

Программисты Silver Castle могут воспользоваться любыми маркерами параметров или централизованными стилями переменных, предоставляемыми pureQuery. Их предпочтения могут основываться на ряде входных параметров или типов входных параметров для встроенного метода. Параметры, переданные в реализацию метода, совпадают с параметрами в SQL. Для определения отображения между параметрами, объявленными в SQL/XQUERY, и параметрами, переданными встроенному методу, pureQuery следует правилам для маркеров параметров. В простейшей форме между двумя наборами параметров существует взаимно-однозначное соответствие. pureQuery может также брать разные типы параметров, такие как pureQuery Beans или java.util.Map.


Обращение к объектам базы данных

Стиль на основе встроенных методов обеспечивает удобные методы и готовую поддержку отображения результатов обращения к базе данных в таблицах и компонентах pureQuery. Перегруженные методы интерфейса Data queryArray(), queryIterator() и queryList() можно использовать для возврата полного набора результатов запроса в виде объектов Array, Iterator или List.

Методы запросов могут возвращать результаты в виде простых типов, компонентов, коллекций и т.п, включая:

  • java.sql.ResultSet;
  • типы Primitive wrapper или простые типы Object, которые поддерживаются непосредственно JDBC (кроме типов, определяемых пользователем);
  • объект java.util.Map, в котором имена столбцов становятся ключами String, а значения столбцов – значениями Object;
  • объекты java.util.Map, сгруппированные в Arrays, Collections или Iterators;
  • отдельные компоненты pureQuery, где пользователь может хранить результаты запроса в pureQuery Bean (аннотации @Column содержат информацию, необходимую для сопоставления столбцов select-list с соответствующими свойствами; подробнее об аннотации pureQuery см. в документации по pureQuery);
  • компоненты pureQuery, сгруппированные в структуры Arrays, Collections или Iterators, где класс возвращаемого компонента передается в качестве параметра.

Когда целевой тип данных выбран, пользователь должен решить, нужно ли применять специальный обработчик для преобразования информации, выбранной из источника данных, в целевой класс. Экземпляры компонентов pureQuery могут создаваться либо с отображением pureQuery по умолчанию из списка выбора оператора SELECT в целевой класс Bean, либо при помощи определяемого пользователем обработчика.


Обращение к списку клиентов Silver Castle

Разработчики Silver Castle хотят проинформировать всех своих клиентов в Австралии о специальном предложении, относящемся к комплектам из солонки и перечницы. Типографии, которые обычно распечатывают подобные письма, принимают в качестве входных данных список java.util.List. Разработчик запрашивает в таблице Customer записи всех клиентов, проживающих в Австралии, и получает последовательность строк. Можно воспользоваться API queryList() и передать страну в качестве входного параметра. Затем полученный список (customerList в следующем примере) передается в типографию, чтобы на письмах напечатали нужные адреса (листинг 4).

Листинг 4. Запрос списка клиентов
      sql = "select * from  PDQ_SC.Customer where Country = ?";
      //Query with List using default handler
      List<Customer> customerList = data.queryList (sql, Customer.class, "Australia");

Определяемые пользователем специальные отображения наборов результатов

Интерфейсы RowHandler и ResultHandler позволяют создавать специальные, определяемые пользователем отображения. pureQuery сообщается, как отображать столбцы результирующего набора для разных объектов Java, при помощи метода handle() в одном из интерфейсов RowHandler или ResultHandler. Row Handlers и Result Handlers предоставляют разработчику значительную гибкость и возможность многократного использования кода, так как для управления деталями выбранного списка они могут применять ResultSetMetaData из ResultSet. Например, можно пропустить некоторые свойства или указать свойства, которые не нужны.

В некоторых случаях разработчику приложения может потребоваться та или иная форма упорядочения результатов запроса в целом. Например, единственной операцией по обработке результатов запроса может быть упорядочение в JSON или XML, или же просто отправка данных в другой (или тот же) источник данных. Для выполнения подобных спецопераций можно воспользоваться интерфейсом ResultHandler.

Отображение одной строки результирующего набора

Интерфейс RowHandler применяется для отображения одной строки результирующего набора на объект. Единственный метод интерфейса RowHandler - handle(). Это общий метод, который при наличии объекта ResultSet и, опционально, экземпляра класса <T> либо создает новый Java-объект класса <T>, либо обновляет данный экземпляр <T>. Если объект ResultSet пуст или была считана последняя строка объекта ResultSet, метод handle() не вызывается. Когда метод handle() вызван, объект ResultSet, переданный методу, помещается в обрабатываемую строку. Метод handle() не должен применять метод next() ко входному объекту ResultSet, так как pureQuery выполняет это действие автоматически.

Отображение набора результатов на объект

Интерфейс ResultHandler применяется для отображения всего набора результатов на объект. Пользователь может задействовать метод handle() из интерфейса ResultHandler для преобразования результатов запроса в другой объект, скажем, XML, который можно передать вместе с другим приложением, принимающим на вход XML.


Редактирование объектов в базе данных

Метод update() интерфейса Data может применяться для внесения единичного изменения в объект базы данных, а метод updateMany() – для внесения пакетных изменений, основанных на одном операторе SQL. Поддерживаются операции INSERT, DELETE и UPDATE.

Одиночные изменения

Метод update() интерфейса Data можно использовать для выполнения одной операции, которая возвращает значение счетчика изменений. В листинге 5 приведен пример обращения к перегруженному (overloaded) методу update() из приложения

Листинг 5. Приложение вызывает перегруженный метод update()
insertSql = "INSERT INTO PDQ_SC.customer (Name, Country, Street, City, " +
            "Province, Zip, Phone) VALUES (:name, :country, :street, " +
        ":city, :province,:zip,:phone)";

//Create an instance of Customer Bean with the values to be inserted
Customer addCustomer = 
new Customer("Customer2","US","BlackBerry Street","San Jose",
                     "Santa Clara","82652","408-273-4856", null); 
//Insert using a Bean
int updateCount = data.update (insertSql, addCustomer);

Пакетные изменения

В интерфейсе Data метод updateMany() указывает на то, что оператор должен выполняться несколько раз. Метод updateMany() позволяет передавать набор, или пакет данных для перебора.

Возвращаемый целочисленный массив, как в JDBC, указывает на успех (и соответствующий счетчик изменений) или неуспех каждого прогона оператора SQL. При этом для индикации наличия ошибок используются значения счетчиков изменений JDBC Statement.EXECUTE_FAILED и SUCCESS_NO_INFO - выдается исключение com.ibm.pdq.runtime.exception.UpdateManyException. Это исключение времени прогона содержит информацию, которую JDBC передает в java.sql.BatchUpdateException.


Редактирование списка клиентов Silver Castle

Один раз в два месяца клиент может присылать в администрацию Silver Castle свой новый адрес или телефон. Разработчики Silver Castle могут редактировать таблицу, пользуясь API для внесения единичных изменений. В листинге 6 приведен пример применения этого API.

Листинг 6. API единичных изменений для редактирования списка
//Update the Street name for Customer
String updateSql = "UPDATE PDQ_SC.customer SET Street= 'Townsend' WHERE name= ?";
int updateCount = data.update (updateSql,"Customer3");
System.out.println ("Rows Updated " + updateCount);

У персонала Silver Castle есть также Web-сайт, где новые клиенты могут подписываться на рассылаемый по почте каталог Silver Castle. Для добавления этих новых имен каждый месяц выполняется утилита обновления базы данных клиентов. Разработчики могут создать задание, которое будет обрабатывать все запросы и вставлять их в базу данных с использованием единственного встроенного метода. В этом случае для эффективного редактирования базы данных они могут воспользоваться API пакетного редактирования (листинг 7).

Листинг 7. API пакетного редактирования
//Example Using UpdateMany
Customer addFirstCustomer = 
new Customer("Customer3","Costa Rica","Main Street","Arenal",
      "La Fortuna","90291","506-375-0273",null); 
Customer addSecondCustomer = 
new Customer("Customer4","Puerto Rico","Church Street",
 "Puerto Nuevo","San Juan","38364","293-484-8244",null); 
ArrayList<Customer> customerList = new ArrayList<Customer>();
customerList.add (addFirstCustomer);
customerList.add (addSecondCustomer);

insertSql = "INSERT INTO PDQ_SC.customer (Name, Country, Street, City, " +
            "Province, Zip, Phone) VALUES (:name, :country, :street, " +
        ":city, :province,:zip,:phone)";
int[] updateCount = data.updateMany( sql, customerList);
if (updateCount != null)
  System.out.println ("Rows Inserted:” + updateCount.length);

Получение автоматически сгенерированных значений

Перегрузка (overloading) метода update() позволяет опционально запрашивать информацию, касающуюся автоматически сгенерированных столбцов. Разработчики Silver Castle могут получать значения, сгенерированные базой данных, любым количеством способов в зависимости от того, что подано на вход метода update. Ниже приведены примеры разных способов, которыми разработчики Silver Castle могут писать свое приложение, чтобы получить сгенерированные значения из базы данных после операции вставки.

Автоматически сгенерированные значения с компонентами pureQuery

В данном примере на вход операции вставки подается компонент pureQuery. Объект Customer определен с аннотацией @GeneratedKey, а столбец CID определен как столбец идентификатора, который всегда генерирует целое число. Значение из столбца CID передается в свойство CID до передачи управления от вызова к методу update(). Здесь автоматически сгенерированное значение - это последовательность в свойстве CID объекта Customer (листинг 8).

Листинг 8. Получение автоматически сгенерированного значения в свойстве CID компонента Customer
insertSql = "INSERT INTO PDQ_SC.customer (Name, Country, Street, City, " +
            "Province, Zip, Phone) VALUES (:name, :country, :street, " +
        ":city, :province,:zip,:phone)";

//Create an instance of Customer Bean with the values to be inserted
Customer customer = 
new Customer("Customer2","US","BlackBerry Street","San Jose",
                     "Santa Clara","82652","408-273-4856", null); 
//Insert using a Bean
int updateCount = data.update (insertSql, customer);
System.out.println ("Generated Key Value:" + customer.cid);

Автоматически генерируемые значения без компонентов pureQuery

Разработчик Silver Castle может передавать результаты без компонентов pureQuery, извлекая автоматически генерируемые значения при помощи следующей версии метода update():

   <T> T update(java.lang.String sql, Class<T> returnClass, 
 String[] columnNames, Object... parameters)

Этот метод возвращает одно или более сгенерированных значений в зависимости от указанного возвращаемого типа. Значение возвращаемого типа Class<T> должно быть одним из двух:

  • Object[].class
  • Простой класс, непосредственно назначаемый из JDBC, такой как Integer.class или String.class

Если возвращаемый тип это простой класс, непосредственно назначаемый из JDBC, данный тип возвращает единственное сгенерированное значение. Значение счетчика изменений не возвращается. В листинге 9 показано, как разработчик из Silver Castle может получить автоматически сгенерированное значение для простого класса (например, int.class).

Листинг 9. Получение автоматически сгенерированного значения для простого класса
Object[] customerArray = new Object[7];
customerArray[0] = "CustomerForGenKey";
customerArray[1] = "US";
customerArray[2] = "Bixby Street";
customerArray[3] = "San Martin";
customerArray[4] = "Santa Clara";
customerArray[5] = "62826";
customerArray[6] = "408-272-6565";

insertSql = "INSERT INTO PDQ_SC.customer (Name, Country, Street," + 
            "City, Province, Zip, Phone) VALUES(?,?,?,?,?,?,?)";
String[] colunmName = new String[] { "cid" };
int i = data.update (insertSql, int.class, colunmName, customerArray);
System.out.println ("AutoGenerated Keys as Int " + i + "\n");

Если возвращаемый тип - это класс Object[].class, первыми n элементами массива будут n сгенерированных значений из столбцов параметра columnName. Последний элемент массива - счетчик изменений. Вот как разработчик Silver Castle может получить сгенерированное значение ключа при помощи Object[]: автоматически сгенерированное значение помещается в Object[0], а счетчик изменений - в Object[1], как показано в листинге 10.

Листинг 10. Ввод автоматически сгенерированного значения в Object[ ]
Object[] customerArray = new Object[7];
customerArray[0] = "CustomerForGenKey";
customerArray[1] = "US";
customerArray[2] = "Barnaby Street";
customerArray[3] = "Gilroy";
customerArray[4] = "Santa Clara";
customerArray[5] = "62823";
customerArray[6] = "408-273-6568";

insertSql = "INSERT INTO PDQ_SC.customer (Name, Country, Street," + 
            " City, Province, Zip, Phone) VALUES(?,?,?,?,?,?,?)";
String[] colunmName = new String[] { "cid" };
Object[] output = data.update (insertSql, Object[].class, 
                  colunmName, customerArray);

Подключаемый механизм обратного вызова с применением интерфейса Hook

Интерфейс com.ibm.pdq.runtime.Hook может использоваться для создания методов, которые исполняются до и после встроенных методов. Предположим, что разработчики Silver Castle знают, что их продукты не могут поставляться клиентам из некоторых стран. В целях данного примера предположим, что это Коста-Рика и Австралия. Интерфейс Hook обеспечивает простой способ, при помощи которого разработчик может однажды определить такую проверку и не добавлять в разные места программы код для проверки страны клиента всякий раз, когда редактируется список клиентов.

Интерфейсы Hook должны регистрироваться в экземплярах объекта Data при их создании. Когда объект Data, используемый для встроенных методов, содержит зарегистрированный Hook, при вызове приложением метода интерфейса Data выполняются следующие шаги:

  • До выполнения любой работы методом интерфейса Data вызывается метод pre() зарегистрированного интерфейса Hook.
  • Вызываемый метод решает свою задачу.
  • Когда вся работа выполнена, вызывается метод post () зарегистрированного интерфейса Hook.

Интерфейс Data, который определяет встроенные методы, содержит ряд методов JDBC для объектов Connection, таких как close (), commit (), rollback (), setAutoCommit () и getAutoCommit (). Методы pre () и post () зарегистрированного интерфейса Hook не заключают эти методы в скобки.

Методы pre () и post () должны определяться с использованием следующих параметров:

  • Строка methodName: pureQuery передает сигнатуру метода методу pre ().
  • Data dataInstance: pureQuery передает объект, реализующий интерфейс Data.
  • SqlStatementType statementType: pureQuery передает тип оператора SQL (например, SELECT, UPDATE, INSERT).
  • Object... параметры: pureQuery передает параметры, передаваемые встроенному методу.
  • Object returnValue: возвращает значение, полученное в результате вызова встроенного метода.

Приведенный в листинге 11 пример демонстрирует использование интерфейса Hook. Разработчик приложения Silver Castle определил методы pre() и post() этого приложения в классе с именем HookCall. Метод pre() проверяет, допустим ли входной параметр «страна клиента», и предотвращает вставку недопустимой строки в базу данных. Проверка результата обращения к методу может осуществляться с применением метода post().

Листинг 11. Использование интерфейса Hook
public static class HookCall implements Hook
{
  public void pre (String methodName, Data objectInstance, 
		    SqlStatementType statementType, Object... parameters)
  {
    String country = ((Customer)parameters[0]).country;
    If (!statementType.equalsIgnoreCase ("update") ||
        !statementType.equalsIgnoreCase("insert")) return;
    if (!(country.equals ("Australia") || country.equals ("Costa Rica")) )
    throw new DataRuntimeException
	  ("This Country " + country + " is not part of our customer base");
  }

  public void post (String methodName, Data objectInstance, 
     Object retValue, SqlStatementType statementType,
     Object... parameters)
  {
    //Do nothing
  }
}

Приложение может зарегистрировать интерфейс Hook, как показано в листинге 12. Входное значение для свойства «страна» в компоненте Customer будет подтверждено, если вызывается метод pre().

Листинг 12. Регистрация интерфейса Hook
Connection con = DriverManager.getConnection(...);
HookCall hookCall = new HookCall ();
Data db = DataFactory.getData(con, hookCall);
sql = "INSERT INTO PDQ_SC.customer (Name, Country, Street, City, Province, Zip, Phone)"
    + "VALUES(:name,:country,:street,:city,:province,:zip,:phone)";
Customer addCustomer2 = new Customer ("Customer2", "Costa Rica", "BlackBerry Street", 
                        "San Jose", "Santa Clara", "82652","408-273-4856", null);
int insertCount = db.update (sql, addCustomer2);

Заключение

В настоящей статье содержится общее введение в стиль программирования на основе встроенных методов pureQuery. Приведено несколько примеров, иллюстрирующих вероятные причины, по которым группа разработчиков приложения pureQuery может воспользоваться встроенными методами. Здесь же приведены основные шаги, необходимые для разработки приложения в стиле встроенных методов. Представлено несколько мощных возможностей данного стиля в качестве потенциальных мотивов выбора программирования в стиле встроенных методов.

Если вы хотите больше узнать о разработке приложений в стиле встроенных методов pureQuery, следуйте по ссылкам, содержащимся в этой статье и в разделе «Ресурсы», которые ведут к онлайновой документации pureQuery, другим статьям и полезным руководствам.

Ресурсы

Комментарии

developerWorks: Войти

Обязательные поля отмечены звездочкой (*).


Нужен IBM ID?
Забыли Ваш IBM ID?


Забыли Ваш пароль?
Изменить пароль

Нажимая Отправить, Вы принимаете Условия использования developerWorks.

 


Профиль создается, когда вы первый раз заходите в developerWorks. Информация в вашем профиле (имя, страна / регион, название компании) отображается для всех пользователей и будет сопровождать любой опубликованный вами контент пока вы специально не укажите скрыть название вашей компании. Вы можете обновить ваш IBM аккаунт в любое время.

Вся введенная информация защищена.

Выберите имя, которое будет отображаться на экране



При первом входе в developerWorks для Вас будет создан профиль и Вам нужно будет выбрать Отображаемое имя. Оно будет выводиться рядом с контентом, опубликованным Вами в developerWorks.

Отображаемое имя должно иметь длину от 3 символов до 31 символа. Ваше Имя в системе должно быть уникальным. В качестве имени по соображениям приватности нельзя использовать контактный e-mail.

Обязательные поля отмечены звездочкой (*).

(Отображаемое имя должно иметь длину от 3 символов до 31 символа.)

Нажимая Отправить, Вы принимаете Условия использования developerWorks.

 


Вся введенная информация защищена.


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=40
Zone=Information Management, Технология Java
ArticleID=431381
ArticleTitle=Создание высокопроизводительных Java-приложений для доступа к данным: Часть 2. Введение в программирование pureQuery
publish-date=09282009