W3docs

Java JDBC Метаданные

Изучите DatabaseMetaData и ResultSetMetaData в Java для получения информации о базе данных и результатах запросов во время выполнения.

Метаданные — это данные о данных: описание структуры результирующего набора и возможностей базы данных, а не сами строки. JDBC предоставляет два интерфейса метаданных, каждый из которых отвечает на разные вопросы. Они лежат в основе универсальных инструментов: средств вывода строк, браузеров схем, ORM и скриптов миграции, которые должны работать без жёстко закодированных знаний о таблицах.

В этой главе рассматриваются оба интерфейса — ResultSetMetaData (столбцы, возвращённые запросом) и DatabaseMetaData (сама база данных и драйвер) — способы чтения кодов SQL-типов, а также запускаемый пример, создающий словарь кодов типов. Предполагается, что вы уже знаете, как открыть JDBC-соединение и перебирать ResultSet.

ResultSetMetaData — описание столбцов запроса

ResultSet содержит строки, а его ResultSetMetaData — описания столбцов. Вызовите rs.getMetaData(), чтобы узнать, какие столбцы вернул запрос: сколько их, каковы их имена и SQL-типы. Именно так универсальная сетка отображает любой запрос:

ResultSetMetaData md = rs.getMetaData();
int n = md.getColumnCount();
for (int i = 1; i <= n; i++) {   // 1-based, of course
  System.out.println(md.getColumnLabel(i)
      + " : " + md.getColumnTypeName(i)
      + " (java.sql.Types " + md.getColumnType(i) + ")");
}

Индексы столбцов начинаются с 1, а не с 0 — getColumnLabel(0) выбрасывает исключение. Наиболее полезные методы:

МетодВозвращает
getColumnCount()количество столбцов в результате
getColumnLabel(i)отображаемое имя с учётом псевдонима AS
getColumnName(i)исходное имя столбца без учёта псевдонимов
getColumnType(i)код int константы java.sql.Types (например, 4 для INTEGER)
getColumnTypeName(i)имя типа от поставщика (например, INT4 в PostgreSQL)
isNullable(i)columnNoNulls, columnNullable или columnNullableUnknown
getPrecision(i) / getScale(i)размер и десятичные разряды, полезно для столбцов NUMERIC

Предпочитайте getColumnLabel вместо getColumnName при отображении заголовков: он учитывает SELECT total AS revenue, поэтому заголовок будет отображаться как revenue.

DatabaseMetaData — описание базы данных

Вызовите conn.getMetaData() для получения сведений о самой базе данных и драйвере: название и версия продукта, поддерживаемые функции, каталог таблиц, столбцов, ключей и индексов.

DatabaseMetaData dbmd = conn.getMetaData();
System.out.println(dbmd.getDatabaseProductName() + " " + dbmd.getDatabaseProductVersion());
System.out.println("supports transactions: " + dbmd.supportsTransactions());

// the schema catalog comes back as ResultSets you read normally
try (ResultSet tables = dbmd.getTables(null, null, "%", new String[]{"TABLE"})) {
  while (tables.next()) System.out.println(tables.getString("TABLE_NAME"));
}

Обратите внимание, что getTables, getColumns и подобные методы возвращают ResultSetы — каталог запрашивается с помощью того же API курсора, что и любые другие данные. Каждая строка getColumns имеет известные метки столбцов, которые вы читаете по имени:

// columns of the "users" table, in any catalog/schema
try (ResultSet cols = dbmd.getColumns(null, null, "users", "%")) {
  while (cols.next()) {
    System.out.println(cols.getString("COLUMN_NAME")
        + " " + cols.getString("TYPE_NAME")
        + (cols.getInt("NULLABLE") == DatabaseMetaData.columnNoNulls ? " NOT NULL" : ""));
  }
}

Четыре аргумента getTables/getColumns — это catalog, schemaPattern, шаблон имени и (для getTables) типы таблиц. null означает «без фильтрации», а % — SQL-маска для «любого имени». Часто используемые дополнительные методы: getPrimaryKeys, getImportedKeys (внешние ключи) и getIndexInfo.

Когда использовать какой интерфейс

  • Используйте ResultSetMetaData, когда у вас есть результат запроса и нужно описать его столбцы — для просмотрщика таблиц, экспортёра CSV или маппера объектов.
  • Используйте DatabaseMetaData, когда вам нужны сведения о базе данных до выполнения запроса — обнаружение функций (поддерживает ли она пакетные обновления? точки сохранения?), обнаружение схемы для инструмента миграции или ветвление SQL по getDatabaseProductName().

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

getColumnType(i) возвращает int — одну из констант java.sql.Types, например INTEGER (4), VARCHAR (12) или TIMESTAMP (93). Сырой int неудобно читать и использовать в switch, поэтому универсальный читатель один раз строит словарь код→имя (с помощью рефлексии над java.sql.Types) и переиспользует его для каждого результирующего набора. Этот же код подскажет, какой типизированный геттер вызывать — getInt, getString, getTimestamp — при сопоставлении столбцов с полями, как это делает маппер на основе PreparedStatement.

Практический пример: словарь кодов типов и отчёт по столбцам

Эта программа строит словарь int→имя для каждой константы java.sql.Types, а затем использует его для описания гипотетического трёхколоночного результата так, как это делал бы ResultSetMetaData — и перечисляет виды вопросов, на которые отвечает DatabaseMetaData — без живой базы данных.

java— editable, runs on the server

Что следует вынести из запуска:

  • Существует 39 стандартных кодов java.sql.Types, и программа строит полную карту код→имя с помощью рефлексии над классом Types. Реальный универсальный читатель строит этот словарь один раз и переиспользует его для каждого результирующего набора.
  • ResultSetMetaData.getColumnType(i) возвращает один из этих кодов int; словарь превращает код 4 в INTEGER, 12 — в VARCHAR, 93 — в TIMESTAMP. Именно этот поиск позволяет инструменту отображать любой запрос без предварительного знания его столбцов.
  • Отчёт по каждому столбцу — имя и тип — это то, что дают getColumnLabel/getColumnType для реального запроса. Это основа просмотрщиков таблиц, экспортёров CSV и ORM, которые сопоставляют столбцы с полями.
  • DatabaseMetaData отвечает на другой класс вопросов: не «что вернул этот запрос», а «что умеет эта база данных» — её название, версию драйвера, поддержку функций и каталог таблиц.
  • Что важно, методы каталога (getTables, getColumns) возвращают ResultSetы, поэтому структуру базы данных вы читаете с помощью того же цикла с курсором, что и данные. Метаданные — это не специальный API, это данные о данных, предоставляемые тем же способом.
Примечание
Количество кодов java.sql.Types (здесь 39) может немного варьироваться в зависимости от версии JDK по мере добавления новых констант. Строите словарь с помощью рефлексии, как показано выше, а не жёстко задавайте количество.

Что изучить далее

  • JDBC ResultSet — API курсора, который возвращают как getMetaData(), так и методы каталога.
  • JDBC Connection — откуда берётся getMetaData() для соединения.
  • JDBC PreparedStatement — обеспечивает сопоставление столбцов на основе метаданных с безопасной привязкой параметров.
  • JDBC TransactionssupportsTransactions() и поддержка точек сохранения сообщаются через DatabaseMetaData.

Практика

Практика
Вы пишете универсальный инструмент, который должен выводить имена и типы столбцов любого переданного ему SQL-запроса без предварительного знания схемы. Какой интерфейс предоставляет эту информацию?
Вы пишете универсальный инструмент, который должен выводить имена и типы столбцов любого переданного ему SQL-запроса без предварительного знания схемы. Какой интерфейс предоставляет эту информацию?
Was this page helpful?