假设你有一个使用Node.js(或其他平台)开发的应用程序,该应用连接到MongoDB数据库(NoSQL)来存储书籍评分(星级数量和评论)。同时,你还有另一个使用Java(或Python、C#、TypeScript等)开发的应用程序,它连接到MariaDB数据库(SQL,关系型)来管理书籍目录(书名、出版年份、页数)。
现在,你需要创建一个报告,显示每本书的书名和评分信息。注意,MongoDB数据库中并不包含书名,而关系型数据库中则没有评分信息。我们需要将由NoSQL应用生成的数据与SQL应用生成的数据进行整合。
A common approach to this is to query both databases independently (using different data sources) and process the data to match by, for example, ISBN (the id of a book) and put the combined information in a new object. This needs to be done in a programming language like Java, TypeScript, C#, Python, or any other imperative programming language that is able to connect to both databases.
A polyglot application
这种方法虽然可行,但数据关联本应是数据库的工作,它们专为此类数据操作而设计。此外,采用这种方法后,SQL应用不再是纯粹的SQL应用,它变成了多数据库混合应用,这增加了维护的复杂性。
通过使用数据库代理如MaxScale,你可以在数据库层级上用最适合数据操作的语言——SQL来关联这些数据。你的SQL应用无需转变为多数据库混合应用。
尽管这需要在基础设施中增加一个额外的元素,但你也获得了数据库代理所提供的所有功能。例如自动故障转移、透明数据屏蔽、拓扑隔离、缓存、安全过滤器等等。
MaxScale是一款强大的智能数据库代理,它理解SQL和NoSQL。它还理解Kafka(用于CDC或数据摄取),但这属于另一个话题。简而言之,通过MaxScale,你可以将NoSQL应用程序连接到一个完全符合ACID原则的关系数据库,并将数据直接存储在与其它SQL应用程序使用的表相邻的位置。
MaxScale允许SQL应用程序消费NoSQL数据。
让我们尝试用MaxScale快速进行一次简单易懂的实验。你需在你的计算机上安装以下内容:
设置MariaDB数据库
使用纯文本编辑器,创建一个新文件并将其保存为docker-compose.yml。文件应包含以下内容:
version: "3.9"
services:
mariadb:
image: alejandrodu/mariadb
environment:
- MARIADB_CREATE_DATABASE=demo
- MARIADB_CREATE_USER=user:Password123!
- MARIADB_CREATE_MAXSCALE_USER=maxscale_user:MaxScalePassword123!
maxscale:
image: alejandrodu/mariadb-maxscale
command: --admin_host 0.0.0.0 --admin_secure_gui false
ports:
- "3306:4000"
- "27017:27017"
- "8989:8989"
environment:
- MAXSCALE_USER=maxscale_user:MaxScalePassword123!
- MARIADB_HOST_1=mariadb 3306
- MAXSCALE_CREATE_NOSQL_LISTENER=user:Password123!
这是一个DOCKER COMPOSE文件。它描述了由Docker创建的一组服务。我们将创建两个服务(或容器)——一个MariaDB数据库服务器和一个MaxScale数据库代理。它们将在您的机器上本地运行,但在生产环境中,通常会将它们部署在不同的物理机上。请记住,这些Docker镜像不适合生产环境!它们旨在适用于快速演示和测试。您可以在GitHub上找到这些镜像的源代码。对于MariaDB的官方Docker镜像,请访问MariaDB在Docker Hub的页面。
之前的Docker Compose文件配置了一个名为demo
的MariaDB数据库服务器(在MariaDB中,数据库和模式是同义词)。同时,创建了一个用户名为user
,密码为Password123!
的用户,该用户对demo
数据库拥有适当的权限。还有一个名为maxscale_user
的用户,密码为MaxScalePassword123!
,这是MaxScale数据库代理用来连接MariaDB数据库的用户。
Docker Compose文件还通过禁用HTTPS(生产环境中切勿如此操作!)、暴露一组端口(稍后详述)以及配置数据库用户和MariaDB数据库代理的位置(通常是IP地址,但此处我们可使用Docker文件中先前定义的容器名称)来配置数据库代理。最后一行创建了一个NoSQL监听器,我们将利用它以MongoDB客户端身份在默认端口(27017)上进行连接。
若要通过命令行启动服务(容器),请转到保存Docker Compose文件的目录,并执行以下命令:
docker compose up -d
下载所有软件并启动容器后,您将获得一个预配置好的MariaDB数据库和MaxScale代理,专为此实验准备。
在MariaDB中创建SQL表
现在,让我们连接到关系型数据库。在命令行中执行以下操作:
mariadb-shell --dsn mariadb://user:'Password123!'@127.0.0.1
确认您能看到demo
数据库:
show databases;
切换到demo
数据库:
use demo;
使用MariaDB Shell连接到数据库。
创建books
表:
CREATE TABLE books(
isbn VARCHAR(20) PRIMARY KEY,
title VARCHAR(256),
year INT
);
插入一些数据。我将采用插入自己的书籍这一陈词滥调:
INSERT INTO books(title, isbn, year)
VALUES
("Vaadin 7 UI Design By Example", "978-1-78216-226-1", 2013),
("Data-Centric Applications with Vaadin 8", "978-1-78328-884-7", 2018),
("Practical Vaadin", "978-1-4842-7178-0", 2021);
通过运行以下命令检查书籍是否已存储在数据库中:
SELECT * FROM books;
使用MariaDB Shell插入数据。
在MariaDB中创建JSON集合
我们尚未安装MongoDB,但我们仍可使用MongoDB客户端(或应用程序)连接并创建集合和文档,就像使用MongoDB一样,只是数据存储在一个功能强大、完全符合ACID且可扩展的关系数据库中。让我们来尝试一下!
在命令行中,使用MongoDB shell工具连接到MongoDB…等等…实际上是MariaDB数据库!运行以下命令:
mongosh
默认情况下,此工具尝试连接到运行在本地机器(127.0.0.1)上、使用默认端口(20017)的MongoDB服务器(这次实际上是MariaDB)。如果一切顺利,运行以下命令时您应该能看到列出的demo
数据库:
show databases
切换到demo
数据库:
use demo
使用Mongo Shell连接到MariaDB。
我们正通过一个非关系型客户端连接到关系型数据库!让我们创建ratings
集合并插入一些数据:
db.ratings.insertMany([
{
"isbn": "978-1-78216-226-1",
"starts": 5,
"comment": "A good resource for beginners who want to learn Vaadin"
},
{
"isbn": "978-1-78328-884-7",
"starts": 4,
"comment": "Explains Vaadin in the context of other Java technologies"
},
{
"isbn": "978-1-4842-7178-0",
"starts": 5,
"comment": "The best resource to learn web development with Java and Vaadin"
}
])
检查这些评分是否已持久化到数据库中:
db.ratings.find()
使用Mongo Shell查询MariaDB数据库。
在MariaDB中使用JSON函数
至此,我们拥有一个单一数据库,对外表现为既是NoSQL(MongoDB)数据库,也是关系型(MariaDB)数据库。我们能够连接到同一数据库,并从MongoDB客户端和SQL客户端进行数据的读写。所有数据均存储在MariaDB中,因此我们可以使用SQL将来自MongoDB客户端或应用程序的数据与来自MariaDB客户端或应用程序的数据进行联接。接下来,我们将探讨MaxScale如何利用MariaDB存储MongoDB数据(集合和文档)。
使用如mariadb-shell
的SQL客户端连接到数据库,并展示demo模式下的表:
show tables in demo;
你应能看到books
和ratings
两张表。ratings
作为MongoDB集合创建。MaxScale将来自MongoDB客户端的命令进行了转换,并创建了一张表以存储数据。现在,让我们查看这张表的结构:
describe demo.ratings;
A NoSQL collection is stored as a MariaDB relational table.
ratings
表包含两个列:
id
:对象ID。doc
:以JSON格式表示的文档。
如果我们检查表的内容,我们会看到所有关于评分的数据都存储在doc
列中,格式为JSON:
SELECT doc FROM demo.ratings \G
NoSQL文档存储在MariaDB数据库中。
让我们回到最初的目标——展示带有评分信息的书籍标题。下面的情况并非如此,但让我们假设一下,ratings
表是一个常规表,具有stars
和comment
列。如果情况确实如此,将此表与books
表连接将非常简单,我们的任务也就完成了:
/* this doesn’t work */
SELECT b.title, r.stars, r.comment
FROM ratings r
JOIN books b USING(isbn)
回到现实。我们需要将实际ratings
表的doc
列转换为可以作为查询中新表使用的关系表达式。类似这样的操作:
/* this still doesn’t work */
SELECT b.title, r.stars, r.comment
FROM ratings rt
JOIN ...something to convert rt.doc to a table... AS r
JOIN books b USING(isbn)
那个东西就是JSON_TABLE
函数。MariaDB包含了一套全面的JSON函数,用于操作JSON字符串。我们将使用JSON_TABLE
函数将doc
列转换为我们可以用于执行SQL连接的关系形式。JSON_TABLE
函数的一般语法如下:
JSON_TABLE(json_document, context_path COLUMNS (
column_definition_1,
column_definition_2,
...
)
) [AS] the_new_relational_table
其中:
json_document
:一个字符串或表达式,返回用于处理的JSON文档。- `
context_path
`: 一个JSON路径表达式,定义了用于作为行来源的节点。
而列定义(如column_definition_1
、column_definition_2
等)具有以下语法:
new_column_name sql_type PATH path_in_the_json_doc [on_empty] [on_error]
结合这些知识,我们的SQL查询将如下所示:
SELECT b.title, r.stars, r.comment
FROM ratings rt
JOIN JSON_TABLE(rt.doc, '$' COLUMNS(
isbn VARCHAR(20) PATH '$.isbn',
stars INT PATH '$.starts',
comment TEXT PATH '$.comment'
)
) AS r
JOIN books b USING(isbn);
在单个SQL查询中结合NoSQL和SQL数据。
我们可以将ISBN值用作MongoDB的ObjectID,进而作为ratings
表中的id
列,但这将留作你的练习(提示:使用_id
而非isbn
在通过MongoDB客户端或应用插入数据时)。
A Word on Scalability
有一种误解认为关系型数据库不能水平扩展(增加更多节点),而NoSQL数据库可以。然而,关系型数据库在不影响ACID属性的情况下进行扩展。MariaDB拥有多种存储引擎,针对不同工作负载量身定制。例如,你可以通过借助Spider实现数据分片来扩展MariaDB数据库。你还可以使用各种存储引擎,以每表为基础处理不同的工作负载。在单个SQL查询中实现跨引擎连接是可能的。
在单一逻辑MariaDB数据库中结合多种存储引擎。
另一种更现代的选择是采用分布式SQL与MariaDB Xpand。分布式SQL数据库通过透明分片技术,对应用程序呈现为一个单一的逻辑关系数据库。它采用无共享架构,可同时扩展读写操作。
A distributed SQL database deployment.
总结
我们的任务至此完成!现在,无论数据是由SQL还是NoSQL应用生成,您的系统都能拥有符合ACID原则且可扩展的全方位数据视图。无需再将应用从NoSQL迁移到SQL,也无需使SQL应用成为数据库多面手。如需了解更多MaxScale的其他功能,请观看此视频或访问文档。
Source:
https://dzone.com/articles/mixing-sql-and-nosql-with-mariadb-and-mongodb