«1. Обзор

Eclipse JNoSQL — это набор API и реализаций, которые упрощают взаимодействие приложений Java с базами данных NoSQL.

В этой статье мы узнаем, как установить и настроить JNoSQL для взаимодействия с базой данных NoSQL. Мы будем работать как с коммуникационным, так и с картографическим слоем.

2. Коммуникационный уровень Eclipse JNoSQL

С технической точки зрения, коммуникационный уровень состоит из двух модулей: Diana API и драйвера.

Хотя API определяет абстракцию для типов баз данных NoSQL, драйвер предоставляет реализации для большинства известных баз данных.

Мы можем сравнить это с JDBC API и драйвером JDBC в реляционных базах данных.

2.1. Eclipse JNoSQL Diana API

Проще говоря, существует четыре основных типа баз данных NoSQL: Key-Value, Column, Document и Graph.

И Eclipse JNoSQL Diana API определяет три модуля:

  1. diana-key-value
  2. diana-column
  3. diana-document

Тип графа NoSQL не поддерживается API, поскольку он уже поддерживается Apache ThinkerPop.

API основан на базовом модуле diana-core и определяет абстракцию общих понятий, таких как конфигурация, фабрика, менеджер, сущность и значение.

Для работы с API нам нужно предоставить зависимость соответствующего модуля от нашего типа базы данных NoSQL.

Таким образом, для базы данных, ориентированной на документы, нам понадобится зависимость diana-document:

<dependency>
    <groupId>org.jnosql.diana</groupId>
    <artifactId>diana-document</artifactId>
    <version>0.0.6</version>
</dependency>

Точно так же мы должны использовать модуль diana-key-value, если рабочая база данных NoSQL ориентирована на ключ-значение. :

<dependency>
    <groupId>org.jnosql.diana</groupId>
    <artifactId>diana-key-value</artifactId>
    <version>0.0.6</version>
</dependency>

И, наконец, модуль diana-column, если он ориентирован на столбцы:

<dependency>
    <groupId>org.jnosql.diana</groupId>
    <artifactId>diana-column</artifactId>
    <version>0.0.6</version>
</dependency>

Самые последние версии можно найти на Maven Central.

2.2. Драйвер Eclipse JNoSQL Diana

Драйвер представляет собой набор реализаций API для наиболее распространенных баз данных NoSQL.

Для каждой базы данных NoSQL существует одна реализация. Если база данных является мультимодельной, драйвер должен реализовать все поддерживаемые API.

Например, cockbase-driver реализует и diana-document, и diana-key-value, потому что Couchbase ориентирован как на документ, так и на ключ-значение.

В отличие от реляционных баз данных, где драйвер обычно предоставляется поставщиком базы данных, здесь драйвер предоставляется Eclipse JNoSQL. В большинстве случаев этот драйвер представляет собой оболочку официальной библиотеки производителя.

Чтобы начать работу с драйвером, мы должны включить API и соответствующую реализацию для выбранной базы данных NoSQL.

Например, для MongoDB нам нужно включить следующие зависимости:

<dependency>
    <groupId>org.jnosql.diana</groupId>
    <artifactId>diana-document</artifactId>
    <version>0.0.6</version>
</dependency>
<dependency>
    <groupId>org.jnosql.diana</groupId>
    <artifactId>mongodb-driver</artifactId>
    <version>0.0.6</version>
</dependency>

Процесс работы с драйвером прост.

Во-первых, нам нужен bean-компонент конфигурации. Прочитав файл конфигурации из пути к классам или значений жесткого кодирования, конфигурация может создать фабрику. Затем мы используем его для создания Manager.

Наконец, менеджер отвечает за отправку и извлечение сущности в базу данных NoSQL и из нее.

В следующих подразделах мы объясним этот процесс для каждого типа базы данных NoSQL.

2.3. Работа с документно-ориентированной базой данных

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

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

Мы можем предоставить эти настройки либо в mongodb-driver.properties, расположенном в пути к классам:

#Define Host and Port
mongodb-server-host-1=localhost:27017

Или как жестко закодированные значения:

Map<String, Object> map = new HashMap<>();
map.put("mongodb-server-host-1", "localhost:27017");

Далее мы создаем компонент конфигурации для типа документа :

DocumentConfiguration configuration = new MongoDBDocumentConfiguration();

Из этого bean-компонента Configuration мы можем создать ManagerFactory:

DocumentCollectionManagerFactory managerFactory = configuration.get();

Неявно метод get() bean-компонента Configuration использует настройки из файла свойств. Мы также можем получить эту фабрику из жестко заданных значений:

DocumentCollectionManagerFactory managerFactory 
  = configuration.get(Settings.of(map));

В ManagerFactory есть простой метод get(), который принимает имя базы данных в качестве параметра и создает менеджер:

DocumentCollectionManager manager = managerFactory.get("my-db");

«

«И, наконец, мы готовы. Менеджер предоставляет все необходимые методы для взаимодействия с базовой базой данных NoSQL через DocumentEntity.

DocumentEntity documentEntity = DocumentEntity.of("books");
documentEntity.add(Document.of("_id", "100"));
documentEntity.add(Document.of("name", "JNoSQL in Action"));
documentEntity.add(Document.of("pages", "620"));
DocumentEntity saved = manager.insert(documentEntity);

Итак, мы могли бы, например, вставить документ:

DocumentQuery query = select().from("books").where("_id").eq(100).build();
List<DocumentEntity> entities = manager.select(query);

Мы также могли бы искать документы:

saved.add(Document.of("author", "baeldung"));
DocumentEntity updated = manager.update(saved);

И аналогичным образом мы могли бы обновить существующий документ:

DocumentDeleteQuery deleteQuery = delete().from("books").where("_id").eq("100").build();
manager.delete(deleteQuery);

И, наконец, мы можем удалить сохраненный документ:

Чтобы запустить пример, нам просто нужно получить доступ к модулю jnosql-diana и запустить приложение DocumentApp.

DefaultDocumentEntity{documents={pages=620, name=JNoSQL in Action, _id=100}, name='books'}
DefaultDocumentEntity{documents={pages=620, author=baeldung, name=JNoSQL in Action, _id=100}, name='books'}
[]

Мы должны увидеть вывод в консоли:

2.4. Работа с базой данных, ориентированной на столбцы

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

<dependency>
    <groupId>org.jnosql.diana</groupId>
    <artifactId>diana-column</artifactId>
    <version>0.0.6</version>
</dependency>
<dependency>
    <groupId>org.jnosql.diana</groupId>
    <artifactId>cassandra-driver</artifactId>
    <version>0.0.6</version>
</dependency>

Процесс работы с базой данных, ориентированной на столбцы, очень похож. Прежде всего, мы добавляем драйвер Cassandra и API столбца в pom:

Далее нам нужны параметры конфигурации, указанные в файле конфигурации, diana-cassandra.properties, в пути к классам. В качестве альтернативы мы могли бы также использовать жестко заданные значения конфигурации.

ColumnConfiguration configuration = new CassandraConfiguration();
ColumnFamilyManagerFactory managerFactory = configuration.get();
ColumnFamilyManager entityManager = managerFactory.get("my-keySpace");

Затем, используя аналогичный подход, мы создадим ColumnFamilyManager и начнем манипулировать ColumnEntity:

ColumnEntity columnEntity = ColumnEntity.of("books");
Column key = Columns.of("id", 10L);
Column name = Columns.of("name", "JNoSQL in Action");
columnEntity.add(key);
columnEntity.add(name);
ColumnEntity saved = entityManager.insert(columnEntity);

Итак, чтобы создать новый объект, давайте вызовем метод insert():

Чтобы запустите образец и посмотрите вывод в консоли, запустите приложение ColumnFamilyApp.

2.5. Работа с базой данных, ориентированной на ключ-значение

В этом разделе мы будем использовать Hazelcast. Hazelcast — это база данных NoSQL, ориентированная на ключ-значение. Для получения дополнительной информации о базе данных Hazelcast вы можете проверить эту ссылку.

<dependency>
    <groupId>org.jnosql.diana</groupId>
    <artifactId>diana-key-value</artifactId>
    <version>0.0.6</version>
</dependency>
<dependency>
    <groupId>org.jnosql.diana</groupId>
    <artifactId>hazelcast-driver</artifactId>
    <version>0.0.6</version>
</dependency>

Процесс работы с типом, ориентированным на ключ-значение, также аналогичен. Мы начинаем с добавления этих зависимостей в pom:

KeyValueConfiguration configuration = new HazelcastKeyValueConfiguration();
BucketManagerFactory managerFactory = configuration.get();
BucketManager entityManager = managerFactory.getBucketManager("books");

Затем нам нужно указать параметры конфигурации. Затем мы можем получить BucketManager, а затем манипулировать KeyValueEntity:

public class Book implements Serializable {

    private String isbn;
    private String name;
    private String author;
    private int pages;

    // standard constructor
    // standard getters and setters
}

Допустим, мы хотим сохранить следующую модель Book:

Book book = new Book(
  "12345", "JNoSQL in Action", 
  "baeldung", 420);
KeyValueEntity keyValueEntity = KeyValueEntity.of(
  book.getIsbn(), book);
entityManager.put(keyValueEntity);

Итак, мы создаем экземпляр Book, а затем сохраняем его, вызывая метод положить();

Optional<Value> optionalValue = manager.get("12345");
Value value = optionalValue.get(); // or any other adequate Optional handling
Book savedBook = value.get(Book.class);

Затем, чтобы получить сохраненный экземпляр Book:

Чтобы запустить пример и просмотреть вывод в консоли, запустите приложение KeyValueApp.

3. Уровень отображения Eclipse JNoSQL

Уровень отображения, Artemis API, представляет собой набор API, которые помогают отображать объекты с аннотациями Java в базы данных NoSQL. Он основан на API-интерфейсе Diana и CDI (внедрение контекста и зависимостей).

Мы можем рассматривать этот API как JPA или ORM, как в мире NoSQL. Этот уровень также предоставляет API для каждого типа NoSQL и один основной API для общих функций.

В этом разделе мы будем работать с документно-ориентированной базой данных MongoDB.

3.1. Необходимые зависимости

Чтобы включить Artemis в приложении, нам нужно добавить зависимость artemis-configuration. Поскольку MongoDB ориентирована на документы, также необходима зависимость artemis-document.

Для других типов баз данных NoSQL мы будем использовать artemis-column, artemis-key-value и artemis-graph.

<dependency>
    <groupId>org.jnosql.artemis</groupId>
    <artifactId>artemis-configuration</artifactId>
    <version>0.0.6</version>
</dependency>
<dependency>
    <groupId>org.jnosql.artemis</groupId>
    <artifactId>artemis-document</artifactId>
    <version>0.0.6</version>
</dependency>
<dependency>
    <groupId>org.jnosql.diana</groupId>
    <artifactId>mongodb-driver</artifactId>
    <version>0.0.6</version>
</dependency>

Также необходим драйвер Diana для MongoDB:

<dependency>
    <groupId>javax</groupId>
    <artifactId>javaee-web-api</artifactId>
    <version>8.0</version>
    <scope>provided</scope>
</dependency>

Artemis основан на CDI, поэтому нам также необходимо предоставить эту зависимость от Maven:

3.2. Файл конфигурации документа

Конфигурация — это набор свойств для данной базы данных, которые позволяют нам предоставлять настройки вне кода. По умолчанию нам нужно предоставить файл jnosql.json в ресурсе META-INF.

[
    {
        "description": "The mongodb document configuration",
        "name": "document",
        "provider": "org.jnosql.diana.mongodb.document.MongoDBDocumentConfiguration",
        "settings": {
            "mongodb-server-host-1":"localhost:27019"
        }
    }
]

Это пример файла конфигурации:

Нам нужно будет указать имя конфигурации выше, установив атрибут name в нашем ConfigurationUnit. Если конфигурация находится в другом файле, ее можно указать с помощью атрибута fileName.

@Inject
@ConfigurationUnit(name = "document")
private DocumentCollectionManagerFactory<MongoDBDocumentCollectionManager> managerFactory;

Учитывая эту конфигурацию, мы создаем фабрику:

@Produces
public MongoDBDocumentCollectionManager getEntityManager() {
    return managerFactory.get("todos");
}

И из этой фабрики мы можем создать DocumentCollectionManager: и Репозиторий.

3.3. Сопоставление

Сопоставление — это управляемый аннотациями процесс, посредством которого модель Entity преобразуется в EntityValue Diana.

Начнем с определения модели Todo:

@Entity
public class Todo implements Serializable {

    @Id("id")
    public long id;

    @Column
    public String name;

    @Column
    public String description;

    // standard constructor
    // standard getters and setters
}

«

«Как показано выше, у нас есть основные аннотации сопоставления: @Entity, @Id и @Column.

Теперь, чтобы манипулировать этой моделью, нам нужен либо класс Template, либо интерфейс Repository.

3.4. Работа с шаблоном

@Inject
DocumentTemplate documentTemplate;

Шаблон является связующим звеном между моделью объекта и API-интерфейсом Diana. Для базы данных, ориентированной на документы, мы начинаем с внедрения bean-компонента DocumentTemplate:

public Todo add(Todo todo) {
    return documentTemplate.insert(todo);
}

И затем мы можем манипулировать сущностью Todo. Например, мы можем создать Todo:

public Todo get(String id) {
    Optional<Todo> todo = documentTemplate
      .find(Todo.class, id);
    return todo.get(); // or any other proper Optional handling
}

Или мы можем получить Todo по id:

public List<Todo> getAll() {
    DocumentQuery query = select().from("Todo").build();
    return documentTemplate.select(query);
}

Чтобы выбрать все объекты, мы создаем DocumentQuery, а затем вызываем метод select(): ~ ~~

public void delete(String id) {
    documentTemplate.delete(Todo.class, id);
}

И, наконец, мы можем удалить объект Todo по идентификатору:

3.5. Работа с репозиторием

В дополнение к классу Template мы также можем управлять сущностями через интерфейс Repository, который имеет методы для создания, обновления, удаления и извлечения информации.

public interface TodoRepository extends Repository<Todo, String> {
    List<Todo> findByName(String name);
    List<Todo> findAll();
}

Чтобы использовать интерфейс репозитория, мы просто предоставляем субинтерфейс репозитория:

В соответствии со следующими соглашениями об именах методов и параметров реализация этого интерфейса предоставляется во время выполнения в виде компонента CDI.

В этом примере все объекты Todo с совпадающим именем извлекаются методом findByName().

@Inject
TodoRepository todoRepository;

Теперь мы можем его использовать:

Квалификатор Database позволяет нам работать с более чем одной базой данных NoSQL в одном приложении. Он поставляется с двумя атрибутами, типом и поставщиком.

@Inject
@Database(value = DatabaseType.DOCUMENT)
TodoRepository todoRepository;

Если база данных мультимодельная, то нам нужно указать, с какой моделью мы работаем:

@Inject
@Database(value = DatabaseType.DOCUMENT, provider="org.jnosql.diana.mongodb.document.MongoDBDocumentConfiguration")
TodoRepository todoRepository;

Дополнительно, если у нас более одной базы данных одной модели, нам нужно указать провайдера:

mvn package liberty:run

Чтобы запустить пример, просто откройте модуль jnosql-artemis и вызовите эту команду:

Эта команда создает, развертывает и запускает сервер Open Liberty благодаря плагину Liberty-maven.

3.6. Тестирование приложения

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

curl -d '{"id":"120", "name":"task120", "description":"Description 120"}' -H "Content-Type: application/json" -X POST http://localhost:9080/jnosql-artemis/todos

Итак, чтобы сохранить класс Todo:

curl -H "Accept: application/json" -X GET http://localhost:9080/jnosql-artemis/todos

и получить все Todo:

curl -H "Accept: application/json" -X GET http://localhost:9080/jnosql-artemis/todos/120

Или получить только одно Todo:

4. Заключение

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

Сначала мы использовали JNoSQL Diana API для взаимодействия с базой данных с помощью низкоуровневого кода. Затем мы использовали JNoSQL Artemis API для работы с дружественными аннотированными моделями Java.