Eclipse JNoSQL 简介
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 定义了三个模块:
- diana-key-value
- diana-column
- diana-document
API 未涵盖 NoSQL 图类型,因为 Apache ThinkerPop 已经涵盖了它。
API 基于核心模块 diana-core,并定义了对常见概念的抽象,例如 Configuration、Factory、Manager、Entity 和 Value。
要使用 API,我们需要为我们的 NoSQL 数据库类型提供相应模块的依赖关系。
因此,对于面向文档的数据库,我们需要 diana-document依赖项:
<dependency>
<groupId>org.jnosql.diana</groupId>
<artifactId>diana-document</artifactId>
<version>0.0.6</version>
</dependency>
同样,如果工作的 NoSQL 数据库是面向键值的,我们应该使用diana-key-value模块:
<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驱动程序
驱动程序是一组用于最常见 NoSQL 数据库的 API 实现。
每个 NoSQL 数据库都有一个实现。如果数据库是多模型的,驱动程序应该实现所有支持的 API。
例如,couchbase-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>
使用驱动程序的过程很简单。
首先,我们需要一个Configuration bean。通过从类路径或硬编码值读取配置文件, Configuration能够创建Factory。然后我们使用它来创建一个Manager。
最后,Manager负责在 NoSQL 数据库中推送和检索实体。
在接下来的小节中,我们将为每个 NoSQL 数据库类型解释这个过程。
2.3. 使用面向文档的数据库
在此示例中,我们将使用嵌入式 MongoDB,因为它很容易上手并且不需要安装。它是面向文档的,以下说明适用于任何其他面向文档的 NoSQL 数据库。
一开始,我们应该提供应用程序与数据库正确交互所需的所有必要设置。在最基本的形式中,我们应该提供 MongoDB 运行实例的Host和Port。
我们可以在类路径上的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");
接下来,我们为文档类型创建Configurationbean:
DocumentConfiguration configuration = new MongoDBDocumentConfiguration();
从这个Configuration bean,我们可以创建一个ManagerFactory:
DocumentCollectionManagerFactory managerFactory = configuration.get();
隐式地,Configuration bean 的get() 方法使用属性文件中的设置。我们也可以从硬编码的值中获取这个工厂:
DocumentCollectionManagerFactory managerFactory
= configuration.get(Settings.of(map));
ManagerFactory有一个简单的方法get(),它将数据库名称作为参数,并创建Manager:
DocumentCollectionManager manager = managerFactory.get("my-db");
最后,我们准备好了。Manager 提供了通过DocumentEntity与底层 NoSQL 数据库交互的 所有必要方法。 因此,例如,我们可以插入一个文档:
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", "blogdemo"));
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=blogdemo, name=JNoSQL in Action, _id=100}, name='books'}
[]
2.4. 使用面向列的数据库
出于本节的目的,我们将使用 Cassandra 数据库的嵌入式版本,因此无需安装。
使用面向列的数据库的过程非常相似。首先,我们在 pom 中添加 Cassandra 驱动和列 API:
<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>
接下来,我们需要在类路径上的配置文件diana-cassandra.properties中指定的配置设置 。或者,我们也可以使用硬编码的配置值。
然后,使用类似的方法,我们将创建一个ColumnFamilyManager并开始操作 ColumnEntity:
ColumnConfiguration configuration = new CassandraConfiguration();
ColumnFamilyManagerFactory managerFactory = configuration.get();
ColumnFamilyManager entityManager = managerFactory.get("my-keySpace");
所以要创建一个新实体,让我们调用*insert()*方法:
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);
要运行示例并在控制台中查看输出,请运行ColumnFamilyApp应用程序。
2.5. 使用面向键值的数据库
在本节中,我们将使用 Hazelcast。Hazelcast 是一个面向键值的 NoSQL 数据库。有关 Hazelcast 数据库的更多信息,您可以查看此链接 。
使用面向键值的类型的过程也类似。我们首先将这些依赖项添加到 pom 中:
<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>
然后我们需要提供配置设置。接下来,我们可以获取一个BucketManager,然后对 KeyValueEntity 进行操作:
KeyValueConfiguration configuration = new HazelcastKeyValueConfiguration();
BucketManagerFactory managerFactory = configuration.get();
BucketManager entityManager = managerFactory.getBucketManager("books");
假设我们要保存以下Book模型:
public class Book implements Serializable {
private String isbn;
private String name;
private String author;
private int pages;
// standard constructor
// standard getters and setters
}
所以我们创建了一个Book实例,然后我们通过调用*put()*方法来保存它;
Book book = new Book(
"12345", "JNoSQL in Action",
"blogdemo", 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);
要运行示例并在控制台中查看输出,请运行KeyValueApp应用程序。
3. Eclipse JNoSQL 映射层
映射层 Artemis API 是一组 API,可帮助将 java 带注释的对象映射到 NoSQL 数据库。它基于 Diana API 和 CDI(上下文和依赖注入)。
我们可以将此 API 视为 JPA 或类似 NoSQL 世界的 ORM。这一层还为每种 NoSQL 类型提供了一个 API,并为常用功能提供了一个核心 API。
在本节中,我们将使用 MongoDB 面向文档的数据库。
3.1. 所需的依赖项
要在应用程序中启用 Artemis,我们需要添加*artemis-configuration * 依赖项。由于 MongoDB 是面向文档的, 因此还需要依赖artemis-document 。
对于其他类型的 NoSQL 数据库,我们将使用artemis-column、artemis-key-value和artemis-graph。
还需要 MongoDB 的 Diana 驱动程序:
<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>
Artemis 是基于 CDI 的,所以我们还需要提供这个 Maven 依赖:
<dependency>
<groupId>javax</groupId>
<artifactId>javaee-web-api</artifactId>
<version>8.0</version>
<scope>provided</scope>
</dependency>
3.2. 文档配置文件
配置是给定数据库的一组属性,让我们在代码之外提供设置。默认情况下,我们需要 在 META-INF 资源下提供jnosql.json文件。
这是配置文件的示例:
[
{
"description": "The mongodb document configuration",
"name": "document",
"provider": "org.jnosql.diana.mongodb.document.MongoDBDocumentConfiguration",
"settings": {
"mongodb-server-host-1":"localhost:27019"
}
}
]
我们需要通过在 ConfigurationUnit 中设置 name 属性来指定上面的配置name。如果配置在不同的文件中,可以使用fileName属性来指定。
给定这个配置,我们创建一个工厂:
@Inject
@ConfigurationUnit(name = "document")
private DocumentCollectionManagerFactory<MongoDBDocumentCollectionManager> managerFactory;
从这个工厂,我们可以创建一个DocumentCollectionManager:
@Produces
public MongoDBDocumentCollectionManager getEntityManager() {
return managerFactory.get("todos");
}
DocumentCollectionManager是一个启用 CDI的bean,它用于Template 和 Repository中。
3.3. 映射
映射是一个注释驱动的过程,通过该过程,Entity模型被转换为 Diana EntityValue。
让我们从定义一个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. 使用模板
模板是实体模型和 Diana API 之间的桥梁。对于面向文档的数据库,我们首先注入DocumentTemplate bean:
@Inject
DocumentTemplate documentTemplate;
然后,我们可以操作Todo实体。例如,我们可以创建一个Todo:
public Todo add(Todo todo) {
return documentTemplate.insert(todo);
}
或者我们可以通过id检索Todo:
public Todo get(String id) {
Optional<Todo> todo = documentTemplate
.find(Todo.class, id);
return todo.get(); // or any other proper Optional handling
}
要选择所有实体,我们构建一个DocumentQuery,然后调用*select()*方法:
public List<Todo> getAll() {
DocumentQuery query = select().from("Todo").build();
return documentTemplate.select(query);
}
最后我们可以通过id删除一个Todo 实体:
public void delete(String id) {
documentTemplate.delete(Todo.class, id);
}
3.5. 使用存储库
除了Template类,我们还可以通过Repository接口管理实体,该接口具有创建、更新、删除和检索信息的方法。
要使用Repository接口,我们只需提供Repository 的子接口:
public interface TodoRepository extends Repository<Todo, String> {
List<Todo> findByName(String name);
List<Todo> findAll();
}
通过以下方法和参数命名约定,此接口的实现在运行时作为 CDI bean 提供。
在此示例中,所有具有匹配名称的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;
要运行示例,只需访问 jnosql-artemis 模块并调用以下命令:
mvn package liberty:run
由于 liberty-maven-plugin ,此命令构建、部署和启动Open Liberty 服务器。
3.6. 测试应用程序
由于应用程序公开了一个 REST 端点,我们可以使用任何 REST 客户端进行测试。这里我们使用了 curl 工具。
所以要保存一个 Todo 类:
curl -d '{"id":"120", "name":"task120", "description":"Description 120"}' -H "Content-Type: application/json" -X POST http://localhost:9080/jnosql-artemis/todos
并获得所有待办事项:
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