JDBC-драйвер#

DataGrid поставляется с JDBC-драйверами, которые позволяют обрабатывать распределенные данные непосредственно через JDBC с помощью стандартных SQL-запросов, например SELECT, INSERT, UPDATE или DELETE.

В настоящее время DataGrid поддерживает два драйвера:

  • легковесный тонкий JDBC-драйвер, который описан в данном разделе;

  • клиентский JDBC-драйвер, который взаимодействует с кластером с помощью клиентского узла и описан в разделе «Клиентский JDBC-драйвер».

Тонкий JDBC-драйвер#

Тонкий JDBC-драйвер — легковесный драйвер по умолчанию, который предоставляет DataGrid. Чтобы начать использовать драйвер, добавьте ignite-core-2.16.0.jar в classpath приложения.

Драйвер подключается к одному из узлов кластера и перенаправляет все запросы на него для окончательного выполнения. Узел обрабатывает распределение запросов и агрегацию результатов. Затем результат отправляется обратно в клиентское приложение.

Строка подключения JDBC может быть отформатирована с использованием одного из двух шаблонов — URL query или semicolon.

Синтаксис строки подключения:

// Шаблон `URL query`.
jdbc:ignite:thin://<hostAndPortRange0>[,<hostAndPortRange1>]...[,<hostAndPortRangeN>][/schema][?<params>]

hostAndPortRange := host[:port_from[..port_to]]

params := param1=value1[&param2=value2]...[&paramN=valueN]

// Шаблон `semicolon`.
jdbc:ignite:thin://<hostAndPortRange0>[,<hostAndPortRange1>]...[,<hostAndPortRangeN>][;schema=<schema_name>][;param1=value1]...[;paramN=valueN]

где:

  • host — обязательный параметр, который определяет хост узла кластера для подключения.

  • port_from — начало диапазона портов для открытия подключения. Если значение параметра не указано, по умолчанию используется 10800.

  • port_to — необязательный параметр. Если значение не указано, по умолчанию используется значение параметра port_from.

  • schema — имя схемы для доступа, по умолчанию используется PUBLIC. Это имя должно соответствовать стандарту SQL ANSI-99. Необрамленные идентификаторы (non-quoted identifiers) не чувствительны к регистру. Обрамленные идентификаторы (quoted identifiers) чувствительны к регистру. При использовании формата с точкой с запятой (semicolon) схема может быть определена как параметр с именем schema.

  • <params> — необязательные параметры.

Имя класса драйвера — org.apache.ignite.IgniteJdbcThinDriver.

Пример открытия JDBC-подключения к узлу кластера

Java#
// Регистрация JDBC-драйвера.
Class.forName("org.apache.ignite.IgniteJdbcThinDriver");

// Открытие JDBC-подключения.
Connection conn = DriverManager.getConnection("jdbc:ignite:thin://xxx.x.x.x");

Примечание

Убедитесь, что вы заключили строку подключения в двойные кавычки (" ") при подключении из среды bash, например: "jdbc:ignite:thin://[address]:[port];user=[username];password=[password]".

Параметры#

В таблице перечислены все параметры, которые поддерживает строка подключения JDBC:

Параметр

Описание

Значение по умолчанию

user

Имя пользователя для SQL-подключения. Этот параметр требуется, если на сервере включена аутентификация

ignite

password

Пароль для SQL-подключения. Требуется, если на сервере включена аутентификация

ignite

distributedJoins

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

false

enforceJoinOrder

Определяет, следует ли принудительно соблюдать порядок соединения таблиц в запросе. Если установлено значение true, оптимизатор запросов не изменяет порядок соединения таблиц

false

collocated

Установите у параметра значение true, если SQL-запрос включает GROUP BY, который группирует результаты по первичному или affinity-ключу.

При выполнении распределенного запроса DataGrid отправляет подзапросы отдельным узлам кластера. Если известно, что элементы запроса размещены на одном узле и группируются по первичному или affinity-ключу, DataGrid оптимизирует производительность и сетевые операции, группируя данные локально на каждом узле

false

autoCloseServerCursor

Определяет, закрываются ли серверные курсоры автоматически после получения последней части результирующего набора. Если этот параметр включен, вызов ResultSet.close() не требует сетевого запроса, что может улучшить производительность. Но если серверный курсор уже закрыт, при попытке вызова ResultSet.getMetadata() может возникнуть исключение, поэтому по умолчанию этот параметр отключен

false

partitionAwareness

Включает режим Partition Awareness. В этом режиме драйвер пытается определить узлы, на которых расположены запрашиваемые данные, и отправлять запросы именно на эти узлы. Подробнее о режиме написано ниже в разделе «Partition Awareness»

false

partitionAwarenessSQLCacheSize

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

Этот кеш SQL-запросов аннулируется при изменении топологии кластера. Оптимальное значение параметра должно соответствовать количеству различных SQL-запросов, которые планируется выполнять

1000

partitionAwarenessPartitionDistributionsCacheSize

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

Этот кеш аннулируется при изменении топологии кластера. Оптимальное значение параметра должно соответствовать количеству уникальных таблиц (групп кеша), которые планируется использовать в запросах

1000

socketSendBuffer

Размер буфера отправки сокета. Если установлено значение 0, используется значение по умолчанию операционной системы

0

socketReceiveBuffer

Размер буфера приема сокета. Если установлено значение 0, используется значение по умолчанию операционной системы

0

tcpNoDelay

Определяет, использовать ли параметр TCP_NODELAY

true

skipReducerOnUpdate

Включает обновления на стороне сервера. При выполнении DML-операции DataGrid извлекает все промежуточные измененные строки и отправляет их инициатору запроса для анализа. Затем он готовит пакеты обновленных значений для отправки на удаленные узлы.

Такой подход может снизить производительность и перегрузить сеть при обработке большого количества записей. Данный флаг позволяет выполнять весь анализ и обновления непосредственно на узлах, где расположены данные. По умолчанию установлено значение false: промежуточные результаты передаются инициатору запроса

false

queryTimeout

Устанавливает количество секунд, в течение которого драйвер ожидает выполнения объекта Statement. Если установлено значение 0, ограничения отсутствуют

0

connectionTimeout

Устанавливает количество миллисекунд, в течение которого JDBC-клиент ожидает ответа от сервера. Если установлено значение 0, ограничения отсутствуют

0

Примеры строк подключения:

  • jdbc:ignite:thin://myHost — подключение к myHost на порту 10800 со всеми настройками по умолчанию.

  • jdbc:ignite:thin://myHost:11900 — подключение к myHost на пользовательском порту 11900 со всеми настройками по умолчанию.

  • jdbc:ignite:thin://myHost:11900;user=*****;password=***** — подключение к myHost на порту 11900 с учетными данными пользователя для аутентификации.

  • jdbc:ignite:thin://myHost:11900;distributedJoins=true&autoCloseServerCursor=true — подключение к myHost на порту 11900 с включенными распределенными соединениями и оптимизацией autoCloseServerCursor.

  • jdbc:ignite:thin://myHost:11900/myschema; — подключение к myHost на порту 11900 и доступ к схеме MYSCHEMA.

  • jdbc:ignite:thin://myHost:11900/"MySchema";lazy=false — подключение к myHost на порту 11900 с отключенным ленивым выполнением запроса (lazy=false) и доступом к MySchema (учитывается регистр букв в названии схемы).

Несколько конечных точек (endpoints)#

Можно включить автоматическое переключение при разрыве соединения — для этого укажите несколько конечных точек (endpoints) в строке подключения. JDBC-драйвер случайным образом выбирает один из указанных адресов для подключения. Если соединение разрывается, драйвер выбирает другой адрес из списка, пока соединение не будет восстановлено. Если все конечные точки недоступны, драйвер прекращает попытки и генерирует исключение.

Пример использования нескольких адресов в строке подключения

Java#
// Регистрация JDBC-драйвера.
Class.forName("org.apache.ignite.IgniteJdbcThinDriver");

// Открытие JDBC-соединения с несколькими конечными точками.
Connection conn = DriverManager
        .getConnection("jdbc:ignite:thin://xxx.xxx.x.xx:xxx,yyy.yyy.y.yy:yyy,zzz.zzz.zz.zzz:zzz");

Partition Awareness#

Внимание

Partition Awareness — экспериментальная функция, ее API и архитектура могут измениться до выхода стабильной версии.

Функция Partition Awareness делает JDBC-драйвер «осведомленным» о распределении данных по партициям внутри кластера. Это позволяет драйверу определять узлы, которые хранят запрашиваемые данные, и отправлять запрос непосредственно на эти узлы (если их адреса указаны в конфигурации драйвера). Такая оптимизация может повысить производительность запросов, которые используют affinity-ключи.

Без функции Partition Awareness JDBC-драйвер подключается только к одному узлу, и все запросы выполняются через него. Если данные хранятся на другом узле, запрос перенаправляется внутри кластера, что создает дополнительную сетевую нагрузку. Функция Partition Awareness устраняет промежуточный шаг с помощью отправки запроса сразу на нужный узел.

Чтобы использовать Partition Awareness, укажите адреса всех серверных узлов в свойствах соединения. Драйвер будет направлять запросы на узлы, где хранятся запрашиваемые данные.

Внимание

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

Для включения функции Partition Awareness добавьте параметр partitionAwareness=true в строку подключения и укажите несколько конечных точек (endpoints):

Java#
Class.forName("org.apache.ignite.IgniteJdbcThinDriver");

Connection conn = DriverManager
        .getConnection("jdbc:ignite:thin://xxx.xxx.x.xx,yyy.yyy.y.yy,zzz.zzz.zz.zzz?partitionAwareness=true");

Примечание

Функция Partition Awareness поддерживается только при использовании стандартной affinity-функции.

Подробнее о связанных параметрах partitionAwarenessSQLCacheSize и partitionAwarenessPartitionDistributionsCacheSize написано выше в таблице в разделе «Параметры».

Конфигурация кластера#

Чтобы принимать и обрабатывать запросы от тонкого JDBC-драйвера, узел кластера привязывается к локальному сетевому интерфейсу на порту 10800 и слушает входящие запросы. Чтобы изменить параметры подключения, используйте экземпляр ClientConnectorConfiguration:

<bean id="ignite.cfg" class="org.apache.ignite.configuration.IgniteConfiguration">
  <property name="clientConnectorConfiguration">
    <bean class="org.apache.ignite.configuration.ClientConnectorConfiguration" />
  </property>
</bean>
IgniteConfiguration cfg = new IgniteConfiguration()
    .setClientConnectorConfiguration(new ClientConnectorConfiguration());

Поддерживаемые параметры:

Параметр

Описание

Значение по умолчанию

host

Имя хоста или IP-адрес для подключения. Если установлено null, используется localhost

null

port

TCP-порт для подключения. Если указанный порт уже используется, DataGrid пытается найти другой доступный порт с помощью свойства portRange

10800

portRange

Определяет количество портов, к которым следует попытаться подключиться. Например, если у параметра port установлено значение 10800, а у portRange — значение 100, сервер попробует подключиться к любому доступному порту в диапазоне [10800, 10900]

100

maxOpenCursorsPerConnection

Максимальное количество курсоров, которые могут быть открыты одновременно для одного соединения

128

threadPoolSize

Количество потоков в пуле, который обрабатывает запросы

MAX(8, CPU cores)

socketSendBufferSize

Размер буфера отправки TCP-сокета. Если установлено значение 0, используется системное значение по умолчанию

0

socketReceiveBufferSize

Размер буфера приема TCP-сокета. Если установлено значение 0, используется системное значение по умолчанию

0

tcpNoDelay

Определяет, использовать ли опцию TCP_NODELAY

true

idleTimeout

Тайм-аут ожидания для клиентских подключений. Клиенты автоматически отключаются от сервера после того, как они остаются неактивными в течение настроенного тайм-аута. Если у параметра установлено значение 0 или отрицательное значение, тайм-аут ожидания отключен

0

isJdbcEnabled

Разрешен ли доступ через JDBC

true

isThinClientEnabled

Разрешен ли доступ через тонкий клиент

true

sslEnabled

Если SSL включен, разрешены только SSL-подключения клиентов. Узел поддерживает только один режим подключения: SSL или plain. Узел не может одновременно принимать оба типа подключения, но этот параметр может отличаться для разных узлов кластера

false

useIgniteSslContextFactory

Использовать ли фабрику SSL-контекста из конфигурации узла

true

sslClientAuth

Требуется ли аутентификация клиента

false

sslContextFactory

Имя класса, который реализует Factory<SSLContext> для обеспечения SSL на стороне узла

null

Тонкий JDBC-драйвер не является потокобезопасным

JDBC-объекты Connections, Statements и ResultSet не являются потокобезопасными. Не используйте операторы (Statement) и результаты (ResultSet) из одного JDBC-соединения в нескольких потоках.

Тонкий JDBC-драйвер защищает от параллелизма (concurrency). Если обнаруживается одновременный доступ, генерируется исключение (SQLException) с сообщением:

"Concurrent access to JDBC connection is not allowed
[ownThread=<guard_owner_thread_name>, curThread=<current_thread_name>]",
SQLSTATE="08006"

Использование SSL#

Тонкий JDBC-драйвер можно настроить для использования SSL для защиты связи с кластером. SSL должен быть настроен и на стороне кластера, и в JDBC-драйвере.

Чтобы включить SSL в JDBC-драйвере, передайте параметр sslMode=require в строке подключения и укажите параметры хранилищ ключей (keystore) и доверенных сертификатов (truststore):

Java#
Class.forName("org.apache.ignite.IgniteJdbcThinDriver");

String keyStore = "keystore/node.jks";
String keyStorePassword = "123456";

String trustStore = "keystore/trust.jks";
String trustStorePassword = "123456";

try (Connection conn = DriverManager.getConnection("jdbc:ignite:thin://127.0.0.1?sslMode=require"
        + "&sslClientCertificateKeyStoreUrl=" + keyStore + "&sslClientCertificateKeyStorePassword="
        + keyStorePassword + "&sslTrustCertificateKeyStoreUrl=" + trustStore
        + "&sslTrustCertificateKeyStorePassword=" + trustStorePassword)) {

    ResultSet rs = conn.createStatement().executeQuery("select 10");
    rs.next();
    System.out.println(rs.getInt(1));
} catch (Exception e) {
    e.printStackTrace();
}

Параметры, которые влияют на соединение SSL/TLS:

Параметр

Описание

Значение по умолчанию

sslMode

Включает SSL-соединение. Доступно два режима: require (SSL включен на клиенте, доступно только SSL-соединение) и disable (SSL отключен на клиенте, поддерживаются только обычные (plain) соединения)

disable

sslProtocol

Название протокола для безопасного соединения. Реализации протокола, которые предоставляются JSSE (Java Secure Socket Extension): SSLv3 (SSL), TLSv1 (TLS), TLSv1.1, TLSv1.2

TLS

sslKeyAlgorithm

Алгоритм управления ключами, который используется для создания диспетчера ключей. В большинстве случаев достаточно значения по умолчанию. Реализации алгоритмов в JSSE: PKIX (X509 или SunPKIX), SunX509

None

sslClientCertificateKeyStoreUrl

URL-адрес файла хранилища клиентских сертификатов (keystore). Это обязательный параметр, так как без него нельзя инициировать SSL-контекст. Если у параметра sslMode установлено значение require и путь к хранилищу ключей не указан в свойствах DataGrid, используется значение системного свойства javax.net.ssl.keyStore

Значение системного свойства javax.net.ssl.keyStore

sslClientCertificateKeyStorePassword

Пароль от хранилища клиентских сертификатов. Если у параметра sslMode установлено значение require и пароль не указан в свойствах DataGrid, используется значение системного свойства javax.net.ssl.keyStorePassword

Значение системного свойства javax.net.ssl.keyStorePassword

sslClientCertificateKeyStoreType

Тип хранилища клиентских сертификатов, который используется при инициализации SSL-контекста. Если у параметра sslMode установлено значение require и тип хранилища не указан в DataGrid, используется значение системного свойства javax.net.ssl.keyStoreType

Значение системного свойства javax.net.ssl.keyStoreType. Если не указано, используется JKS

sslTrustCertificateKeyStoreUrl

URL-адрес файла хранилища доверенных сертификатов (truststore). Этот параметр необязателен, но должен быть настроен один из двух параметров: sslTrustCertificateKeyStoreUrl или sslTrustAll.

Если у параметра sslMode установлено значение require и путь к хранилищу доверенных сертификатов не указан в DataGrid, используется значение системного свойства javax.net.ssl.trustStore

Значение системного свойства javax.net.ssl.trustStore

sslTrustCertificateKeyStorePassword

Пароль от хранилища доверенных сертификатов. Если у параметра sslMode установлено значение require и пароль не указан в DataGrid, используется значение системного свойства javax.net.ssl.trustStorePassword

Значение системного свойства javax.net.ssl.trustStorePassword

sslTrustCertificateKeyStoreType

Тип хранилища доверенных сертификатов. Если у параметра sslMode установлено значение require и тип хранилища не указан в DataGrid, используется значение системного свойства javax.net.ssl.trustStoreType

Значение системного свойства javax.net.ssl.trustStoreType. Если не указано, используется JKS

sslTrustAll

Отключает проверку сертификатов сервера. Чтобы доверять любым сертификатам сервера (включая отозванные, просроченные или самоподписанные SSL-сертификаты), установите значение true.

Важно: не включайте параметр sslTrustAll в производственной среде или в сети, которой вы не полностью доверяете (особенно если используется публичный интернет)

false

sslFactory

Имя класса пользовательской реализации Factory<SSLSocketFactory>. Если у параметра sslMode установлено значение require и указана фабрика, будет использоваться пользовательская фабрика вместо стандартной JSSE. В этом случае другие SSL-параметры игнорируются

null

Реализация SSL в тонком JDBC-драйвере основана на JSSE и использует два файла хранилища ключей (keystore) Java:

  • sslClientCertificateKeyStoreUrl — хранилище клиентских сертификатов, которое содержит ключи и сертификат клиента.

  • sslTrustCertificateKeyStoreUrl — хранилище доверенных сертификатов, которое содержит сертификаты для проверки подлинности сервера.

Хранилище доверенных сертификатов — необязательный параметр, но должен быть настроен один из двух параметров: sslTrustCertificateKeyStoreUrl или sslTrustAll.

Использование параметра sslTrustAll

Не включайте параметр sslTrustAll в производственной среде или в сети, которой вы не полностью доверяете (особенно если используется публичный интернет).

Если нет возможности использовать собственную реализацию или метод настройки SSLSocketFactory, можно использовать параметр sslFactory JDBC-драйвера. Этот параметр должен содержать имя класса, который реализует интерфейс Factory<SSLSocketFactory>. Класс должен быть доступен загрузчику классов JDBC-драйвера.

DataSource#

Объект DataSource используется как развертываемый объект, который можно найти по логическому имени через сервис именования JNDI. JDBC-драйвер реализует класс org.apache.ignite.IgniteJdbcThinDataSource, который поддерживает интерфейс DataSource и позволяет использовать его вместо стандартного JDBC-подключения.

Помимо общих свойств DataSource, IgniteJdbcThinDataSource поддерживает все специфические параметры DataGrid, которые можно передавать в строке подключения JDBC. Например, свойство distributedJoins можно установить и переустановить с помощью метода IgniteJdbcThinDataSource#setDistributedJoins().

Подробнее о IgniteJdbcThinDataSource написано в официальной документации Apache Ignite.

Примеры использования#

Чтобы начать обработку данных в кластере, создайте объект JDBC-соединения одним из способов:

Java#
// Открытие JDBC-соединения с помощью `DriverManager`.
Connection conn = DriverManager.getConnection("jdbc:ignite:thin://xxx.xxx.x.xx");

или

Java#
// Открытие JDBC-соединения с помощью `DataSource`.
IgniteJdbcThinDataSource ids = new IgniteJdbcThinDataSource();
ids.setUrl("jdbc:ignite:thin://xxx.x.x.x");
ids.setDistributedJoins(true);

Connection conn = ids.getConnection();

После этого можно выполнять стандартные SQL-запросы (SELECT, INSERT, MERGE, UPDATE, DELETE) и использовать DML-операторы для изменения данных.

SELECT#

Java#
// Запрос людей определенного возраста с помощью подготовленного выражения (`PreparedStatement`).
PreparedStatement stmt = conn.prepareStatement("select name, age from Person where age = ?");

stmt.setInt(1, 30);

ResultSet rs = stmt.executeQuery();

while (rs.next()) {
    String name = rs.getString("name");
    int age = rs.getInt("age");
    // ...
}

Также можно использовать DML-операторы для изменения данных.

INSERT#

Java#
// Вставка новой записи в таблицу `Person` с ключом типа `long`.
PreparedStatement stmt = conn
        .prepareStatement("INSERT INTO Person(_key, name, age) VALUES(CAST(? as BIGINT), ?, ?)");

stmt.setInt(1, 1);
stmt.setString(2, "John Smith");
stmt.setInt(3, 25);

stmt.execute();

MERGE#

Java#
// Объединение (merge) записи в таблицу `Person` с ключом типа `long`.
PreparedStatement stmt = conn
        .prepareStatement("MERGE INTO Person(_key, name, age) VALUES(CAST(? as BIGINT), ?, ?)");

stmt.setInt(1, 1);
stmt.setString(2, "John Smith");
stmt.setInt(3, 25);

stmt.executeUpdate();

UPDATE#

Java#
// Обновление данных в таблице `Person`.
conn.createStatement().
  executeUpdate("UPDATE Person SET age = age + 1 WHERE age = 25");

DELETE#

Java#
// Удаление записей из таблицы `Person`.
conn.createStatement().execute("DELETE FROM Person WHERE age = 25");

Потоковая передача данных#

JDBC-драйвер поддерживает потоковую передачу (bulk streaming) данных с помощью команды SET. Подробнее о ней написано в подразделе «SET STREAMING» раздела «Управляющие команды».

Коды ошибок#

JDBC-драйвер передает коды ошибок в классе java.sql.SQLException, что облегчает обработку исключений на стороне приложения. Чтобы получить код ошибки, используйте метод java.sql.SQLException.getSQLState(). Он возвращает строку, которая содержит код ошибки SQLSTATE, определенный стандартами ANSI SQL.

Пример обработки ошибок в JDBC

Java#
PreparedStatement ps;

try {
    ps = conn.prepareStatement("INSERT INTO Person(id, name, age) values (1, 'John', 'unparseableString')");
} catch (SQLException e) {
    switch (e.getSQLState()) {
    case "0700B":
        System.out.println("Conversion failure");
        break;

    case "42000":
        System.out.println("Parsing error");
        break;

    default:
        System.out.println("Unprocessed error: " + e.getSQLState());
        break;
    }
}

В таблице ниже описаны все коды ошибок ANSI SQLSTATE, которые поддерживаются в JDBC-драйвере DataGrid. В будущем этот список может быть расширен.

Коды ошибок:

Код

Описание

0700B

Ошибка преобразования данных, например строковое выражение не может быть интерпретировано как число или дата

0700E

Недопустимый уровень изоляции транзакции

08001

Драйвер не смог установить соединение с кластером

08003

Соединение находится в закрытом состоянии. Это произошло неожиданно

08004

Соединение отклонено кластером

08006

Ошибка ввода-вывода во время связи с кластером

22004

Недопустимое NULL-значение

22023

Неподдерживаемый тип параметра

23000

Нарушение целостности данных

24000

Недопустимое состояние ResultSet

0A000

Запрашиваемая операция не поддерживается

40001

Конфликт при одновременном обновлении данных

42000

Исключение при разборе SQL-запроса

50000

Внутренняя ошибка. Этот код не определен стандартом ANSI и относится к специфическим ошибкам DataGrid. Подробнее об ошибке написано в сообщении в java.sql.SQLException