RussianLDP Рейтинг@Mail.ru
WebMoney: 
WMZ Z294115950220 
WMR R409981405661 
WME E134003968233 
Visa 
4274 3200 2453 6495 

Глава 5. MySQL NoSQL Connector for JavaScript

Эта секция предоставляет информацию о MySQL NoSQL Connector for JavaScript, ряде адаптеров Node.js для NDB Cluster и MySQL Server, доступных с NDB 7.3.1, которые позволяют написать приложения JavaScript для Node.js с использованием данных MySQL.

5.1. Обзор MySQL NoSQL Connector for JavaScript

Этот соединитель отличается по многим ключевым отношениям от большинства других соединителей MySQL и API. Интерфейс асинхронный, после встроенной модели событий Node.js. Кроме того, это использует модель объекта области для хранения данных. Запросы получают данные в форме полностью порожденных объектов, а не как строки и столбцы.

MySQL Node.js включает 2 драйвера. Драйвер ndb получает доступ к NDB напрямую, с применением NDB API (см. главу 2). MySQL Server для него не нужен. Драйвер mysql применяет MySQL Server и зависит от модуля node-mysql Node.js из https://github.com/felixge/node-mysql/. Независимо от драйвера не требуются никакие SQL-операторы, используя Connector for JavaScript, проекты Node.js используют объекты данных для всех запросов к базе данных.

5.2. Установка JavaScript Connector

Эта секция покрывает базовую установку, установку MySQL JavaScript Connector и его зависимостей. Connector требует Node.js и NDB Cluster, можно установить их в любом порядке. Кроме того, mysql-js требует драйвер node-mysql. Сборка Connector также требует, чтобы у вашей системы был рабочий компилятор C++, такой как gcc или Microsoft Visual Studio.

Чтобы поставить все предпосылки для соединителя JavaScript, включая node-mysql, необходимо выполнить следующие шаги:

  1. Node.js. Если у вас нет Node.js на вашей системе, можно получить его из http://nodejs.org/download/. В дополнение к исходному коду предварительно построенные двоичные модули и инсталляторы доступны для многих платформ. У многих дистрибутивов Linux также есть Node.js в их хранилищах (вы, возможно, должны добавить альтернативное хранилище в своем диспетчере пакетов).

    NDB 7.3.1 требует Node.js 0.7.9 или более ранний из-за зависимости от node-waf. NDB 7.3.2 и позже использует node-gyp (см. https://npmjs.org/package/node-gyp) и должны работать с Node.js 0.8.0 и позже.

    Независимо от метода, которым вы получаете Node.js, имейте в виду, что архитектура версии, которую вы устанавливаете, должна соответствовать архитектуре двоичных модулей NDB Cluster: вы не можете, например, установить JavaScript Connector, имея 64-bit Node.js и 32-bit NDB Cluster. Если вы не знаете архитектуру своей существующей установки Node.js, можно определить это, проверив значение global.process.arch.

  2. NDB Cluster. Если NDB Cluster, включая все заголовки и файлы библиотеки, еще не установлен в системе, установите его (см. NDB Cluster Installation).

    Как упомянуто ранее, необходимо удостовериться, что архитектура (32 бита или 64 бита) является той же самой для NDB Cluster и Node.js. Можно проверить архитектуру существующей установки NDB Cluster в выводе ndb_mgm -V.

  3. Драйвер node-mysql. mysql-js также требует рабочей установки node-mysql с https://github.com/felixge/node-mysql/. Можно установить драйвер, используя команду npm install, посмотрите веб-сайт проекта об идентификаторе пакета и рекомендуемой версии.

Как только требования выполнены, можно найти файлы для установки соединителя MySQL для JavaScript в каталоге share/nodejs установки NDB Cluster. Если вы установили NDB Cluster как RPM, это /usr/share/mysql/nodejs. Чтобы использовать инструмент npm, чтобы выполнить установку лучшего предположения без любого вмешательства пользователя, перейдите в каталог share/nodejs, затем используйте npm:

shell> npm install .

Заключительный символ точки (.) требуется. Обратите внимание на то, что необходимо управлять этой командой в подкаталоге share/node.js каталога установки NDB Cluster.

Можно проверить установку, используя поставляемую тестовую программу. Это требует управления NDB Cluster, включая MySQL Server с базой данных test. Клиент mysql должен быть в пути.

Чтобы выполнить тесты, перейдите в каталог test:

shell> node driver

По умолчанию всеми серверами управляют на местной машине, используя порты по умолчанию, это может быть изменено, редактируя файл test/test_connection.js, который произведен, управляя набором тестов. Если этот файл не присутствует (см. Bug #16967624), можно скопировать share/nodejs/test/lib/test_connection_js в каталог test.

Если вы установили NDB Cluster не по умолчанию, вы, возможно, должны экспортировать LD_LIBRARY_PATH, чтобы позволить набор тестов. Набор тестов также требует, чтобы база данных test была доступна на сервере MySQL.

NDB 7.3.1 также предлагает альтернативный скрипт сборки в share/node.js/setup, это было удалено в NDB 7.3.2 и позже.

5.3. Описание Connector for JavaScript API

Эта секция содержит описания прототипа и другую информацию для MySQL Connector for JavaScript.

5.3.1. Batch

Этот класс представляет пакет операций.

Batch extends Context
execute(Function(Object error)
callback);

Выполните пакет. Когда он выполняется, все операции выполняются, отзыв для каждой операции вызывают, когда та операция выполняется (операции не выполняются ни в каком конкретном порядке). Функция execute() также вызывает callback.

Пакет выполняется в контексте текущего состояния сессии: включен autocommit, если транзакция не была начата, это также включает способ блокировки по умолчанию и ключ разделения.

clear();

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

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

Эта функция не требует никаких аргументов.

getSession();

Получите сессию, из которой была создан этот пакет.

Эта функция не требует никаких аргументов.

5.3.2. Context

Context это супертип Session и Batch. Это содержит функции, которые выполняются немедленно, если вызвано от сессии, или когда пакет выполняется.

Mynode действительно имеет любое понятие о пользователе и не определяет никаких подобных свойств.

find(Function constructor,
Object keys,
Function(Object error,
Object instance[, ...])
callback[, ...]);

find(String tableName,
Object keys,
Function(Object error,
Object instance[, ...])
callback[, ...]);

Найдите определенный экземпляр на основе значения уникального ключа или первичного ключа.

Можно использовать любую из двух версий этой функции. В первой версии параметр constructor это функция конструктора отображенного объекта области. Альтернативно можно использовать tableName во втором варианте функции.

Для обеих версий find() keys может иметь любой тип. Ключ должен однозначно определить единственную строку в базе данных. Если keys простой тип (число или последовательность), тогда тип параметра должен быть тем же самым типом или совместим с типом первичного ключа отображенного объекта. Иначе свойства взяты от параметра и соответствуют именам свойств в отображении. Свойства первичного ключа используются, если все присутствуют, другие свойства проигнорированы. Если keys не может использоваться, чтобы определить первичный ключ, имена свойств, соответствующие столбцам уникального ключа, используются вместо этого. Если никакие полные свойства первичного или уникального ключа не найдены, сообщают об ошибке. Возвращенный объект загружается на основе отображения и текущего значения в базе данных.

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

load(Object instance,
Function(Object error)
callback);

Загрузите определенный экземпляр, согласовав его первичный или уникальный ключ со строкой базы данных, не создавая новый объект области. Это в отличие от find(), который создает новый отображенный объект области.

instance должен иметь его значение первичного или уникального ключа или набор. Отображенные значения в объекте загружаются на основе текущего значения в базе данных. Неотображенные свойства в объекте не изменяются.

Свойства первичного ключа используются, если все присутствуют и все другие свойства проигнорированы, иначе имена свойств, соответствующие столбцам уникального ключа, используются. Если никакие полные свойства первичного или уникального ключа не могут быть найдены, сообщают об ошибке.

Функция callback вызвана с параметрами, обеспеченными, когда операция закончилась. error это объект Node.js Error, см. раздел 5.3.4.

persist(Object instance,
Function(Object error)
callback);

persist(Function constructor,
Object values,
Function(Object error)
callback);

persist(String tableName,
Object values,
Function(Object error)
callback);

Вставьте экземпляр в базу данных, если экземпляр не существует в базе данных, в этом случае об исключении сообщает функция callback. Сгенерированные значения присутствуют в случае, когда выполняется callback is.

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

Во всех трех случаях callback вызвана с параметрами, если таковые имеются, когда операция закончена. error это объект Node.js Error, см. раздел 5.3.4.

remove(Object instance,
Function(Object error)
callback);

remove(Function constructor,
Object keys,
Function(Object error)
callback);

remove(String tableName,
Object keys,
Function(Object error)
callback);

Удалите экземпляр класса из базы данных первичным или уникальным ключом.

Есть три версии remove(), они позволяют вам удалять экземпляр, относясь к объекту instance, функции constructor или по имени таблицы. Объект instance должен содержать значения ключа, которые однозначно определяют единственную строку в базе данных. Иначе, если keys поставляемый конструктором функции или именем таблицы простой тип (Number или String), тогда тип параметра должен иметь тот же самый тип или тип, совместимый с типом первичного ключа отображенного объекта. Если keys не простой тип, свойства взяты от параметра и соответствуют именам свойств в отображении. Свойства первичного ключа используются, если все присутствуют и другие свойства проигнорированы. Если keys не определяет первичный ключ, имена свойств, соответствующие уникальному ключу, используются вместо этого. Если никакие полные свойства первичного или уникального ключа не найдены, сообщают об ошибке callback.

Все три версии remove() вызывают функцию callback с параметрами, если таковые имеются, когда операция завершена. error это объект Node.js Error, см. раздел 5.3.4.

update(Object instance,
       Function(Object error)
       callback);

update(Function constructor,
       keys,
       values,
       Function(Object error)
       callback);

update(String tableName,
       keys,
       values,
       Function(Object error) callback);

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

Как с методами, ранее показанными для сохраняющихся экземпляров и удаления их от базы данных, update() существует в трех вариантах, которые позволяют вам использовать instance как объект, объект constructor с keys или по tableName и keys.

Области уникального ключа keys определяют, который instance должен быть обновлен. Объект values предоставляет значения, которые будут обновлены. Если объект keys содержит все области, соответствующие первичному ключу, первичный ключ определяет экземпляр. В противном случае уникальные ключи выбраны недетерминированным способом.

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

save(Object instance,
     Function(Object error)
     callback);

save(Function constructor,
     Object values,
     Function(Object error)
     callback);

save(String tableName,
     Object values,
     Function(Object error)
     callback);

Сохраните экземпляр в базе данных, не проверяя на существование. Если экземпляр уже существует, он обновляется (как будто вы использовали update()), иначе это создается (как будто использовали persist()). Свойство id экземпляра используется, чтобы определить, какой экземпляр должен быть сохранен. Как с update(), persist() и remove(), этот метод позволяет вам определять экземпляр, используя объект, конструктор или имя таблицы.

Все три версии save() вызывают функцию callback с любыми параметрами, когда операция была закончена. error это объект Node.js Error, см. раздел 5.3.4.

Boolean isBatch()

Context также выставляет метод isBatch(), который возвращает true, если Context это Batch и false, если это Session . isBatch() не берет аргументов.

5.3.3. Конвертер

Классы конвертера преобразовывают между типами MySQL и типами данных JavaScript. Если пользователь поставляет конвертер JavaScript, он используется для чтения и записи базы данных.

У конвертеров есть несколько целей, включая следующие:

  • Преобразовать между типами MySQL DECIMAL и предпочтительной сервисной библиотекой фиксированной точности JavaScript.

  • Преобразовать между типами MySQL BIGINT и предпочтительной сервисной библиотекой пользователя JavaScript крупных чисел.

  • Преобразовать в последовательную форму произвольные объекты приложения в символы или столбцы двоичных данных.

ndb бэкэнд также использует конвертеры, чтобы поддержать столбцы SET и ENUM. mysql бэкэнд не использует их.

Классу Converter определили интерфейс:

function Converter() {}:
Converter.prototype = {
  "toDB": function(obj) {},
  "fromDB": function(val) {}
};

Converter должен осуществить следующие две функции:

  1. toDB( obj): Преобразуйте объект приложения obj в форму, которая может быть сохранена в базе данных.

  2. fromDB(val ): Преобразуйте значение val из базы данных в формат объекта приложения.

Каждая функция возвращает результат преобразования.

Вызовы конвертера связаны следующими способами:

  • При записи к базе данных, сначала вызван зарегистрированный FieldConverter, если есть. Позже вызван любой зарегистрированный TypeConverter.

  • Читая от базы данных, сначала вызван зарегистрированный TypeConverter, если есть. Позже вызван любой зарегистрированный FieldConverter.

5.3.4. Ошибки

Объект Errors содержит коды ошибок и сообщение, выставленное адаптерами MySQL Node.js.

var Errors;
Errors = {
  /* Standard-defined classes, SQL-99 */
  "02000" : "No Data",
  // connection errors
  "08000" : "Connection error",
  "08001" : "Unable to connect to server",
  "08004" : "Connection refused",
  // data errors
  "22000" : "Data error",
  "22001" : "String too long",
  "22003" : "Numeric value out of range",
  "22008" : "Invalid datetime",
  // Constraint violations
  // 23000 includes both duplicate primary key and duplicate unique key
  "23000" : "Integrity Constraint Violation",
  // misc. errors
  "25000" : "Invalid Transaction State",
  "2C000" : "Invalid character set name",
  "42S02" : "Table not found",
  "IM001" : "Driver does not support this function",
  /* Implementation-defined classes (NDB) */
  "NDB00" : "Refer to ndb_error for details"
};

5.3.5. Mynode

Этот класс используется, чтобы произвести и получить информацию о сессиях (объекты Session). Чтобы создать экземпляр, используйте функцию Node.js require() с именем драйвера:

var nosql = require("mysql-js");

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

ConnectionProperties(nameOrProperties);

Можно также создать собственный объект ConnectionProperties, поставляя список свойств и значений к новому объекту ConnectionProperties вместо названия адаптера. Тогда можно использовать этот объект, чтобы установить свойства связи для новой сессии, как показано здесь:

var NdbConnectionProperties = {
  "implementation" : "ndb",
  "ndb_connectstring" : "localhost:1186",
  "database": "test",
  "mysql_user": "root",
  "ndb_connect_retries" : 4,
  "ndb_connect_delay" : 5,
  "ndb_connect_verbose" : 0,
  "linger_on_close_msec": 500,
  "use_ndb_async_api" : false,
  "ndb_session_pool_min" : 4,
  "ndb_session_pool_max" : 100,
};

var sharePath = '/usr/local/mysql/share/nodejs';   // path to share/nodejs
var nosql = require(sharePath);
var dbProperties = nosql.ConnectionProperties(NdbConnectionProperties);

Также возможно получить объект со свойствами связи адаптера по умолчанию, после которых можно обновить отобранное количество этих свойств, а затем использовать измененный объект, чтобы установить свойства связи для сессии, как показано здесь:

var sharePath = '/usr/local/mysql/share/nodejs';   // path to share/nodejs
var spi = require(sharePath + "/Adapter/impl/SPI");    // under share/nodejs
var serviceProvider = spi.getDBServiceProvider('ndb');
var NdbConnectionProperties = serviceProvider.getDefaultConnectionProperties();
NdbConnectionProperties.mysql_user = 'nodejs_user';
NdbConnectionProperties.database = 'my_nodejs_db';
var dbProperties = nosql.ConnectionProperties(NdbConnectionProperties);

Объект ConnectionProperties включает следующие свойства:

  • implementation: Для приложений Node.js, использующих NDB Cluster, это всегда ndb.

  • ndb_connectstring: Строка подключения NDB Cluster для соединения с сервером управления.

  • database: Название базы данных MySQL, чтобы использовать.

  • mysql_user: Имя пользователя MySQL.

  • ndb_connect_retries: Сколько раз, чтобы повторить неудавшуюся связь до тайм-аута, используйте число меньше 0 для этого значения, чтобы продолжать пробовать связь без остановки.

  • ndb_connect_delay: Интервал в секундах между повторениями связи.

  • ndb_connect_verbose: 1 или 0: 1 позволяет дополнительный вывод консоли во время связи.

  • linger_on_close_msec: Когда клиент закрывает DBConnectionPool, основная связь сохранена открытой этого число миллисекунд в случае, если другой клиент попытается использовать ее.

  • use_ndb_async_api: Если true, некоторые операции выполняются, используя асинхронные вызовы, чтобы улучшить параллельность. Если false, количество операций ограничивается одной на рабочий поток.

  • ndb_session_pool_min: Минимум объектов DBSession на NdbConnectionPool.

  • ndb_session_pool_max: Максимум объектов DBSession на NdbConnectionPool.

    Каждый NdbConnectionPool обслуживает пул DBSession объектов, наряду с их основными Ndb объектами. Этот параметр вместе с ndb_session_pool_min задает рекомендации для размера этого пула.

Конструктор TableMapping также видим как функция верхнего уровня. Можно получить отображение по имени или при помощи существующего отображения:

TableMapping(tableName);
TableMapping(tableMapping);
openSession(properties,
            mappings,
            Function(err, Session)
            callback);

Соединитесь с источником данных и получите Session в функции callback. Это эквивалентно запросу connect() (см. позже в этой секции), а затем запросу getSession() в SessionFactory, который возвращен в функции обратного вызова.

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

Участник внедрения объекта properties определяет внедрение Session.

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

Многократные таблицы и конструкторы могут быть переданы openSession() как элементы во множестве.

connect(properties,
        mappings,
        Function(err,
        SessionFactory) callback);

Соединитесь с источником данных, чтобы получить SessionFactory в функции callback. Чтобы получить Session , необходимо вызвать getSession() на этой SessionFactory, чье внедрение определяется участником внедрения объекта properties.

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

Многократные таблицы и конструкторы могут быть переданы как элементы во множестве.

Array getOpenSessionFactories()

Получите множество всех объектов SessionFactory, которые были созданы этим модулем.

Следующие функции часть API, но не предназначаются для прикладного использования. Они являются частью взаимодействия между Mynode и SessionFactory.

  • Connection()

  • getConnectionKey()

  • getConnection()

  • newConnection()

  • deleteFactory()

5.3.6. Сессия

Сессия это путь доступа основного пользователя к базе данных. Класс Session моделирует такую сессию.

Session extends Context
getMapping(Object parameter,
           Function(Object err,
           Object mapping)
           callback);

Получите отображения для таблицы или класса.

parameter может быть именем таблицы, отображенной функцией конструктора или объектом области. Эта функция возвращает полностью решенный объект TableMapping.

Batch createBatch()

Создает новый пустой пакет для сбора многократных операций, которые будут выполнены вместе. В приложении можно вызвать эту функцию так, как показывают здесь:

var nosql = require("mysql-js");
var myBatch = nosql.createBatch();
Array listBatches():

Возвратите множество, элементы которого состоят из всех текущих партий, принадлежащих этой сессии.

Transaction currentTransaction();

Получите текущий объект Transaction.

void close(Function(Object error)
           callback);

Закройте эту сессию. Должна быть вызвана, когда сессия больше не необходима.

boolean isClosed();

Вернет true, если эта сессия закрывается.

void setLockMode(String lockMode);

Установите способ блокировки для операций чтения. Это немедленно вступает в силу и остается в силе, пока сессия не закрывается, или этот метод не вызывают снова. lockMode это 'EXCLUSIVE', 'SHARED' или 'NONE'.

Array listTables(databaseName,
                 callback);

Перечислите все таблицы в базе данных databaseName.

TableMetadata
getTableMetadata(String databaseName
, String tableName,
callback);

Получите метаданные для таблицы tableName в базе данных databaseName.

5.3.7. SessionFactory

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

openSession(Object mappings,
            Function(Object error,
            Session session)
            callback);

Откройте объект сессии базы данных. Таблица mappings утверждена в начале сессии. Ресурсы, требуемые для сессий, ассигнуются заранее, если те ресурсы не доступны, метод возвращает ошибку в отзыве.

Array getOpenSessions();

Получите все открытые сессии, которые были созданы этой SessionFactory.

close(Function(Error err));

Закройте связь с базой данных. Это гарантирует надлежащее разъединение. Переданная функция вызвана, когда операция закрытия завершена.

5.3.8. TableMapping и FieldMapping

TableMapping описывает отображение объекта области в применении к таблице, хранимой в базе данных. Отображение таблицы default это то, которое отображает каждую колонку в таблице к области с тем же самым именем.

TableMapping = {
  String table:"" ,
  String database :"" ,
  boolean mapAllColumns : true,
  Array fields: null
};

Члены table и data это названия таблицы и базы данных, соответственно. mapAllColumns, если true, создает FieldMapping по умолчанию для всех колонок, не перечисленных в fields, таким образом, что этим всем колонкам, не отображенным явно, дают отображение по умолчанию области с тем же самым именем. fields хранит множество объектов FieldMapping, это может также быть единственным FieldMapping.

FieldMapping описывает единственную область в объекте области. Нет никакого публичного конструктора для этого объекта, можно создать FieldMapping, используя TableMapping.mapField(), или можно использовать литералы FieldMapping непосредственно в конструкторе TableMapping.

FieldMapping = {
  String fieldName :"" ,
  String columnName:"" ,
  Boolean persistent: true,
  Converter converter : null
};

fieldName и columnName это названия поля и колонки, где эта область сохранена, соответственно, в объекте области. Если persistent = true (по умолчанию), область сохранена в базе данных. converter определяет класс Converter, если есть, чтобы использовать с этой областью (по умолчанию пустой указатель).

Конструктор TableMapping может взять любое название таблицы (возможно квалифицированное с именем базы данных) или литерал TableMapping.

TableMapping mapField(String fieldName,
                      [String columnName],
                      [Converter converter],
                      [Boolean persistent])

Создайте отображение области для названной области отображенного объекта. Единственный обязательный параметр это fieldName, который предоставляет имя области в объекте приложения JavaScript. Остающиеся параметры дополнительные и могут появиться в любом порядке. Текущий объект TableMapping возвращен.

columnName определяет название колонки базы данных, которая отображена к этому полю объекта. Если опущено, columnName отображено к тому же самому значению, как fieldName. converter может использоваться, чтобы поставлять класс Converter , который выполняет преобразование между типами данных базы данных и JavaScript. По умолчанию null. persistent определяет, сохранена ли область в базе данных, по умолчанию true.

Если persistent = false, то columnName и converter не могут использоваться.

TableMapping applyToClass(Function constuctor)

Присоедините TableMapping к constructor для отображенных объектов. После того, как это сделано, любой объект, созданный от конструктора, будет характеризоваться как отображенный экземпляр, с которым несколько форм соответствующего метода Session и Batch могут использоваться.

Например, приложение может построить экземпляр, который только частично полон, затем использовать Session.load(), чтобы наполнить его всеми отображенными областями от базы данных. После того, как приложение изменяет экземпляр, Session.save() запишет его назад. Точно так же Session.find() может взять отображенного конструктора, получить объект, основанный на ключах, а затем использовать конструктор, чтобы создать полный объект области.

5.3.9. TableMetadata

Объект TableMetadata представляет таблицу. Это объект, возвращенный в отзыве getTable(). indexes[0] представляет внутренний первичный ключ таблицы.

TableMetadata = {
  database : "",   // Database name
  name : "",   // Table Name
  columns: {},   // ordered array of ColumnMetadata objects
  indexes: {},   // array of IndexMetadata objects
  partitionKey : {},   // ordered array of column numbers in the partition key
};

Объект ColumnMetadata представляет столбец таблицы.

ColumnMetadata = {
  /* Required Properties */
  name : "",   // column name
  columnNumber : -1,   // position of column in table, and in columns array
  columnType : "",   // a ColumnTypes value
  isIntegral : false ,   // true if column is some variety of INTEGER type
  isNullable : false ,   // true if NULLABLE
  isInPrimaryKey : false ,   // true if column is part of PK
  isInPartitionKey : false ,   // true if column is part of partition key
  columnSpace: 0 ,   // buffer space required for encoded stored value
  defaultValue : null,   // default value for column: null for default NULL;
  // undefined for no default; or a type-appropriate
  // value for column
  /* Optional Properties, depending on columnType */
  /* Group A: Numeric */
  isUnsigned : false ,   //true for UNSIGNED
  intSize: null,   //1,2,3,4, or 8 if column type is INT
  scale: 0 ,    //DECIMAL scale
  precision: 0 ,   //DECIMAL precision
  isAutoincrement: false ,   //true for AUTO_INCREMENT columns
  /* Group B: Non-numeric */
  length : 0 ,   //CHAR or VARCHAR length in characters
  isBinary : false ,   //true for BLOB/BINARY/VARBINARY
  charsetNumber: 0 ,   //internal number of charset
  charsetName: "",   //name of charset
};

Объект IndexMetadata представляет индекс таблицы. Массив indexes из TableMetadata содержит объект IndexMetadata на индекс таблицы.

NDB осуществляет первичный ключ как заказанный и как уникальный индекс, и мог бы быть рассмотрен через адаптер API NDB как два индекса, но через адаптер MySQL как единственный индекс, который уникален и заказан. Мы терпим это несоответствие и отмечаем, что внедрение в Adapter/api должно рассматривать эти два описания как эквивалентные.

IndexMetadata = {
  name : "",   // Index name; undefined for PK
  isPrimaryKey : true,   // true for PK; otherwise undefined
  isUnique : true,   // true or false
  isOrdered: true,   // true or false; can scan if true
  columns: null,   // an ordered array of column numbers
};

Объекты ColumnMetaData columnType должны быть действительными значениями ColumnTypes, как показано в определении этого объекта здесь:

ColumnTypes =["TINYINT", "SMALLINT", "MEDIUMINT", "INT", "BIGINT",
              "FLOAT", "DOUBLE", "DECIMAL", "CHAR", "VARCHAR", "BLOB",
              "TEXT", "DATE", "TIME", "DATETIME", "YEAR", "TIMESTAMP",
              "BIT", "BINARY", "VARBINARY"];

5.3.10. Транзакция

Транзакция всегда автоматическая или явная. Если она автоматическая (autocommit), каждая операция выполняется как часть новой транзакции, которая автоматически передается.

Начало, передача и отмена транзакции

begin();

Начните транзакцию. Никакие аргументы не требуются. Если транзакция уже активна, исключение брошено.

commit(Function(Object error)
       callback);

Передайте транзакцию.

Этот метод берет в качестве собственного аргумента функцию callback, которая возвращает ошибочный объект.

rollback(Function(Object 
error) callback);

Отмените транзакцию. Об ошибках сообщают в функции callback.

Методы информации о транзакции

Boolean isActive();

Определите, активна ли в настоящее время данная транзакция. Вернет true, если транзакция активная, и false иначе.

isActive() не требует никаких аргументов.

setRollbackOnly();

Отметьте транзакцию как только для обратной перемотки. Как только это сделано, commit() отменяет транзакцию и бросает исключение, rollback() отменяет транзакцию, но не бросает исключение. Чтобы отметить транзакцию как только для обратной перемотки, вызовите метод setRollbackOnly().

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

boolean getRollbackOnly();

Определите, была ли транзакция отмечена как только для обратной перемотки. Вернет true, если транзакция была так отмечена. setRollbackOnly() не берет аргументов.

5.4. Применение MySQL JavaScript Connector: примеры

Эта секция содержит много примеров, выполняющих основные операции по базе данных, такие как получение, вставка или удаление строк таблицы. Исходные тексты этих файлов также можно найти в share/nodejs/samples в каталоге установки NDB Cluster.

5.4.1. Требования для примеров

Требования к программному обеспечению для примеров в следующих нескольких секциях следующие:

  • Работающая установка Node.js.

  • Рабочие установки ndb и mysql-js.

  • Адаптер mysql-js также требует рабочей установки драйвера node-mysql из https://github.com/felixge/node-mysql/.

Раздел 5.2 описывает процесс установки для всех этих требований.

База данных-образец, таблица и данные. Все примеры используют типовую таблицу tweet в базе данных test. Эта таблица определяется как в следующем CREATE TABLE:

CREATE TABLE IF NOT EXISTS tweet(id CHAR(36) NOT NULL PRIMARY KEY,
                                 author VARCHAR(20), message VARCHAR(140),
                                 date_created TIMESTAMP,
                                 KEY idx_btree_date_created (date_created),
                                 KEY idx_btree_author(author)) ENGINE=NDB;

Таблица tweet может быть составлена запуском SQL-скрипта create.sql в клиенте mysql. Можно сделать это, вызвав mysql в системной оболочке, как показано здесь:

shell> mysql < create.sql

Все примеры также используют два модуля, определенные в файле lib.js, чье содержание воспроизводится здесь:

# FILE: lib.js
"use strict";
var udebug = unified_debug.getLogger("samples/lib.js");
var exec = require("child_process").exec;
var SQL = {};

/* Pseudo random UUID generator */
var randomUUID = function() {
  return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
    var r = Math.random()*16|0, v = c == 'x' ? r : (r&0x3|0x8);
    return v.toString(16);
  });
};

/* Tweet domain object model */
var Tweet = function(author, message) {
  this.id = randomUUID();
  this.date_created = new Date();
  this.author = author;
  this.message = message;
};

/* SQL DDL Utilities */
var runSQL = function(sqlPath, source, callback) {
  function childProcess(error, stdout, stderr) {
    udebug.log('harness runSQL process completed.');
    udebug.log(source + ' stdout: ' + stdout);
    udebug.log(source + ' stderr: ' + stderr);
    if (error !== null)
    {
       console.log(source + 'exec error: ' + error);
    } else {
      udebug.log(source + ' exec OK');
    }
    if (callback)
    {
       callback(error);
    }
  }
  var p = mysql_conn_properties;
  var cmd = 'mysql';
  if (p)
  {
     if (p.mysql_socket)     { cmd += " --socket=" + p.mysql_socket; }
     else if (p.mysql_port)  { cmd += " --port=" + p.mysql_port; }
     if (p.mysql_host)     { cmd += " -h " + p.mysql_host; }
     if (p.mysql_user)     { cmd += " -u " + p.mysql_user; }
     if (p.mysql_password) { cmd += " --password=" + p.mysql_password; }
  }
  cmd += ' <' + sqlPath;
  udebug.log('harness runSQL forking process...');
  var child = exec(cmd, childProcess);
};

SQL.create =  function(suite, callback) {
  var sqlPath = path.join(suite.path, 'create.sql');
  udebug.log_detail("createSQL path: " + sqlPath);
  runSQL(sqlPath, 'createSQL', callback);
};

SQL.drop = function(suite, callback) {
  var sqlPath = path.join(suite.path, 'drop.sql');
  udebug.log_detail("dropSQL path: " + sqlPath);
  runSQL(sqlPath, 'dropSQL', callback);
};

/* Exports from this module */
exports.SQL               = SQL;
exports.Tweet             = Tweet;

Наконец, модуль, используемый для случайного создания данных, включен в файл ndb_loader/lib/RandomData.js:

# FILE: RandomData.js
var assert = require("assert");

function RandomIntGenerator(min, max)
{
  assert(max > min);
  var range = max - min;
  this.next = function()
  {
    var x = Math.floor(Math.random() * range);
    return min + x;
  };
}

function SequentialIntGenerator(startSeq)
{
  var seq = startSeq - 1;
  this.next = function()
  {
    seq += 1;
    return seq;
  };
}

function RandomFloatGenerator(min, max, prec, scale)
{
  assert(max > min);
  this.next = function()
  {
    var x = Math.random();
    /* fixme! */
    return 100 * x;
  };
}

function RandomCharacterGenerator()
{
  var intGenerator = new RandomIntGenerator(32, 126);
  this.next = function()
  {
    return String.fromCharCode(intGenerator.next());
  };
}

function RandomVarcharGenerator(length)
{
  var lengthGenerator = new RandomIntGenerator(0, length),
      characterGenerator = new RandomCharacterGenerator();
  this.next = function()
  {
    var i = 0,
        str = "",
        len = lengthGenerator.next();
    for (; i < len ; i++) str += characterGenerator.next();
    return str;
  }
}

function RandomCharGenerator(length)
{
  var characterGenerator = new RandomCharacterGenerator();
  this.next = function()
  {
    var i = 0,
        str = "";
    for(; i < length ; i++) str += characterGenerator.next();
    return str;
  };
}

function RandomDateGenerator()
{
  var generator = new RandomIntGenerator(0, Date.now());
  this.next = function()
  {
    return new Date(generator.next());
  };
}

function RandomGeneratorForColumn(column)
{
  var g = {},
      min, max, bits;

  switch(column.columnType.toLocaleUpperCase())
  {
    case "TINYINT":
    case "SMALLINT":
    case "MEDIUMINT":
    case "INT":
    case "BIGINT":
      if (column.isInPrimaryKey)
      {
         g = new SequentialIntGenerator(0);
      }
      else {
        bits = column.intSize * 8;
        max = column.isUnsigned ? Math.pow(2,bits)-1 : Math.pow(2, bits-1);
        min = column.isUnsigned ? 0 : 1 - max;
        g = new RandomIntGenerator(min, max);
      }
      break;
    case "FLOAT":
    case "DOUBLE":
    case "DECIMAL":
      g = new RandomFloatGenerator(0, 100000); // fixme
      break;
    case "CHAR":
      g = new RandomCharGenerator(column.length);
      break;
    case "VARCHAR":
      g = new RandomVarcharGenerator(column.length);
      break;
    case "TIMESTAMP":
      g = new RandomIntGenerator(0, Math.pow(2,32)-1);
      break;
    case "YEAR":
      g = new RandomIntGenerator(1900, 2155);
      break;
    case "DATE":
    case "TIME":
    case "DATETIME":
      g = new RandomDateGenerator();
      break;
    case "BLOB":
    case "TEXT":
    case "BIT":
    case "BINARY":
    case "VARBINARY":
    default:
      throw("UNSUPPORTED COLUMN TYPE " + column.columnType);
      break;
  }
  return g;
}

function RandomRowGenerator(table)
{
  var i = 0,
      generators = [];
  for (; i < table.columns.length ; i++) {
    generators[i] = RandomGeneratorForColumn(table.columns[i]);
  }
  this.newRow = function()
  {
    var n, col, row = {};
    for (n = 0; n < table.columns.length ; n++)
    {
      col = table.columns[n];
      row[col.name] = generators[n].next();
    }
    return row;
  };
}
exports.RandomRowGenerator = RandomRowGenerator;
exports.RandomGeneratorForColumn = RandomGeneratorForColumn;

5.4.2. Пример: поиск строк

# FILE: find.js
var nosql = require('..');
var lib = require('./lib.js');
var adapter = 'ndb';
global.mysql_conn_properties = {};

var user_args = [];
// *** program starts here ***
// analyze command line

var usageMessage =
  "Usage: node find key\n" +
  "          -h or --help: print this message\n" +
  "         -d or --debug: set the debug flag\n" +
  "  --mysql_socket=value: set the mysql socket\n" +
  "    --mysql_port=value: set the mysql port\n" +
  "    --mysql_host=value: set the mysql host\n" +
  "    --mysql_user=value: set the mysql user\n" +
  "--mysql_password=value: set the mysql password\n" +
  "              --detail: set the detail debug flag\n" +
  "   --adapter=<adapter>: run on the named adapter (e.g. ndb or mysql)\n"
  ;

// handle command line arguments
var i, exit, val, values;
for (i = 2; i < process.argv.length ; i++)
{
  val = process.argv[i];
  switch (val)
  {
    case '--debug':
    case '-d':
      unified_debug.on();
      unified_debug.level_debug();
      break;
    case '--detail':
      unified_debug.on();
      unified_debug.level_detail();
      break;
    case '--help':
    case '-h':
      exit = true;
      break;
    default:
      values = val.split('=');
      if (values.length === 2)
      {
         switch (values[0])
         {
           case '--adapter':
             adapter = values[1];
             break;
           case '--mysql_socket':
             mysql_conn_properties.mysql_socket = values[1];
             break;
           case '--mysql_port':
             mysql_conn_properties.mysql_port = values[1];
             break;
           case '--mysql_host':
             mysql_conn_properties.mysql_host = values[1];
             break;
           case '--mysql_user':
             mysql_conn_properties.mysql_user = values[1];
             break;
           case '--mysql_password':
             mysql_conn_properties.mysql_password = values[1];
             break;
           default:
             console.log('Invalid option ' + val);
            exit = true;
         }
      } else {
        user_args.push(val);
      }
    }
  }
  if (user_args.length !== 1)
  {
     console.log(usageMessage);
     process.exit(0);
  };
  if (exit)
  {
     console.log(usageMessage);
     process.exit(0);
  }
  console.log('Running find with adapter', adapter, user_args);
  //create a database properties object
  var
    dbProperties = nosql.ConnectionProperties(adapter);
  // create a basic mapping
  var
  annotations = new nosql.TableMapping('tweet').applyToClass(lib.Tweet);
  //check results of find
  var
    onFind = function(err, object)
    {
      console.log('onFind.');
      if (err)
      {
         console.log(err);
      } else {
        console.log('Found: ' + JSON.stringify(object));
      }
      process.exit(0);
  };

// find an object
var onSession = function(err, session)
{
  if (err)
  {
     console.log('Error onSession.');
     console.log(err);
     process.exit(0);
  } else {
    session.find(lib.Tweet, user_args[0], onFind);
  }
};

// connect to the database
nosql.openSession(dbProperties, annotations, onSession);

5.4.3. Вставка строк

# FILE: insert.js
var nosql = require('..');
var lib = require('./lib.js');
var adapter = 'ndb';
global.mysql_conn_properties = {};

var user_args = [];
// *** program starts here ***
// analyze command line

var usageMessage =
  "Usage: node insert author message\n" +
  "          -h or --help: print this message\n" +
  "         -d or --debug: set the debug flag\n" +
  "  --mysql_socket=value: set the mysql socket\n" +
  "    --mysql_port=value: set the mysql port\n" +
  "    --mysql_host=value: set the mysql host\n" +
  "    --mysql_user=value: set the mysql user\n" +
  "--mysql_password=value: set the mysql password\n" +
  "              --detail: set the detail debug flag\n" +
  "   --adapter=<adapter>: run on the named adapter (e.g. ndb or mysql)\n"
  ;

// handle command line arguments
var i, exit, val, values;

for (i = 2; i < process.argv.length ; i++)
{
  val = process.argv[i];
  switch (val) {
  case '--debug':
  case '-d':
    unified_debug.on();
    unified_debug.level_debug();
    break;
  case '--detail':
    unified_debug.on();
    unified_debug.level_detail();
    break;
  case '--help':
  case '-h':
    exit = true;
    break;
  default:
    values = val.split('=');
    if (values.length === 2) {
      switch (values[0]) {
      case '--adapter':
        adapter = values[1];
        break;
      case '--mysql_socket':
        mysql_conn_properties.mysql_socket = values[1];
        break;
      case '--mysql_port':
        mysql_conn_properties.mysql_port = values[1];
        break;
      case '--mysql_host':
        mysql_conn_properties.mysql_host = values[1];
        break;
      case '--mysql_user':
        mysql_conn_properties.mysql_user = values[1];
        break;
      case '--mysql_password':
        mysql_conn_properties.mysql_password = values[1];
        break;
      default:
        console.log('Invalid option ' + val);
        exit = true;
      }
    } else {
      user_args.push(val);
    }
  }
}

if (user_args.length !== 2) {
  console.log(usageMessage);
  process.exit(0);
};
if (exit)
{
   console.log(usageMessage);
   process.exit(0);
}
console.log('Running insert with adapter', adapter, user_args);
//create a database properties object
var
  dbProperties = nosql.ConnectionProperties(adapter);
// create a basic mapping
var annotations = new nosql.TableMapping('tweet').applyToClass(lib.Tweet);
//check results of insert
var onInsert = function(err, object) {
  console.log('onInsert.');
  if (err)
  {
     console.log(err);
  } else {
    console.log('Inserted: ' + JSON.stringify(object));
  }
  process.exit(0);
};

// insert an object
var onSession = function(err, session) {
  if (err) {
     console.log('Error onSession.');
     console.log(err);
     process.exit(0);
  } else {
    var data = new lib.Tweet(user_args[0], user_args[1]);
    session.persist(data, onInsert, data);
  }
};
// connect to the database
nosql.openSession(dbProperties, annotations, onSession);

5.4.4. Удаление строк

FILE: delete.js
var nosql = require('..');
var lib = require('./lib.js');
var adapter = 'ndb';
global.mysql_conn_properties = {};

var user_args = [];
// *** program starts here ***
// analyze command line

var usageMessage =
  "Usage: node delete message-id\n" +
  "          -h or --help: print this message\n" +
  "         -d or --debug: set the debug flag\n" +
  "  --mysql_socket=value: set the mysql socket\n" +
  "    --mysql_port=value: set the mysql port\n" +
  "    --mysql_host=value: set the mysql host\n" +
  "    --mysql_user=value: set the mysql user\n" +
  "--mysql_password=value: set the mysql password\n" +
  "              --detail: set the detail debug flag\n" +
  "   --adapter=<adapter>: run on the named adapter (e.g. ndb or mysql)\n"
  ;

// handle command line arguments
var i, exit, val, values;
for(i = 2; i < process.argv.length ; i++)
{
  val = process.argv[i];
  switch (val)
  {
    case '--debug':
    case '-d':
      unified_debug.on();
      unified_debug.level_debug();
      break;
    case '--detail':
      unified_debug.on();
      unified_debug.level_detail();
      break;
    case '--help':
    case '-h':
      exit = true;
      break;
    default:
      values = val.split('=');
      if (values.length === 2)
      {
         switch (values[0])
         {
           case '--adapter':
             adapter = values[1];
             break;
           case '--mysql_socket':
             mysql_conn_properties.mysql_socket = values[1];
             break;
           case '--mysql_port':
             mysql_conn_properties.mysql_port = values[1];
             break;
           case '--mysql_host':
             mysql_conn_properties.mysql_host = values[1];
             break;
           case '--mysql_user':
             mysql_conn_properties.mysql_user = values[1];
             break;
           case '--mysql_password':
             mysql_conn_properties.mysql_password = values[1];
             break;
           default:
             console.log('Invalid option ' + val);
             exit = true;
         }
      } else {
        user_args.push(val);
      }
    }
  }
  if (user_args.length !== 1)
  {
     console.log(usageMessage);
     process.exit(0);
  };
  if (exit)
  {
     console.log(usageMessage);
     process.exit(0);
  }
  console.log('Running delete with adapter', adapter, user_args);

//create a database properties object
var
  dbProperties = nosql.ConnectionProperties(adapter);
// create a basic mapping
var annotations = new nosql.TableMapping('tweet').applyToClass(lib.Tweet);
// check results of delete
var onDelete = function(err, object)
{
  console.log('onDelete.');
  if (err)
  {
     console.log(err);
  } else {
    console.log('Deleted: ' + JSON.stringify(object));
  }
  process.exit(0);
};

// delete an object
var onSession = function(err, session)
{
  if (err) {
     console.log('Error onSession.');
     console.log(err);
     process.exit(0);
  } else {
    var tweet = new lib.Tweet();
    tweet.id = user_args[0];
    session.remove(tweet, onDelete, user_args[0]);
  }
};
// connect to the database
nosql.openSession(dbProperties, annotations, onSession);

Поиск

 

Найди своих коллег!

Вы можете направить письмо администратору этой странички, Алексею Паутову. mailto:alexey.v.pautov@mail.ru