混合使用MariaDB和MongoDB的SQL与NoSQL

假设你有一个在Node.js(或任何其他平台)上开发的应用程序。这个应用程序连接到一个MongoDB数据库(NoSQL),用于存储对书籍的评价(给出的星级数量和评论)。再假设你有另一个在Java(或Python、C#、TypeScript...等)上开发的应用程序。这个应用程序连接到一个MariaDB数据库(SQL,关系型),用于管理书籍目录(标题、出版年份、页数)。

你被要求创建一个报告,展示每本书的标题和评分信息。注意,MongoDB数据库不包含书籍的标题,而关系型数据库不包含评分。我们需要混合由NoSQL应用程序创建的数据和由SQL应用程序创建的数据。

一个常见的方法是独立查询这两个数据库(使用不同的数据源),并处理数据以匹配,例如,按ISBN(书籍的ID)进行匹配,并将组合的信息放入一个新对象中。这需要在Java、TypeScript、C#、Python或能够连接到这两个数据库的任何其他命令式编程语言中完成。

squids.cn 目前可体验全网zui低价RDS,免费的迁移工具DBMotion、SQL开发工具等

多语种应用程序

这种方法是可行的。但是,数据的联接是数据库的工作。它们为这种数据操作而生。此外,使用这种方法,SQL应用程序不再只是一个纯SQL应用程序;它成为一个数据库多语种,这增加了复杂性,使其更难维护。

使用像MaxScale这样的数据库代理,您可以使用最适合数据的语言------SQL,在数据库级别连接这些数据。您的SQL应用程序不需要成为多语种。

尽管这在基础架构中需要额外的元素,但你还可以获得数据库代理所提供的所有功能。例如自动故障转移、透明数据屏蔽、拓扑隔离、缓存、安全过滤器等。

MaxScale是一个功能强大、智能的数据库代理,理解SQL和NoSQL。它也了解Kafka(用于CDC或数据摄取),但那是另一个话题。简而言之,有了MaxScale,你可以将你的NoSQL应用程序连接到一个完全符合ACID的关系数据库,并将数据存储在其他SQL应用程序使用的表旁边。

MaxScale允许SQL应用程序使用NoSQL数据

让我们在一个简单且易于跟随的MaxScale实验中尝试这最后一种方法。你需要在你的计算机上安装以下内容:

  • Docker
  • mariadb-shell工具
  • mongosh工具

设置MariaDB数据库

使用一个简单的文本编辑器,创建一个新文件并保存为docker-compose.yml。该文件应包含以下内容:

ini 复制代码
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镜像,请前往Docker Hub上的MariaDB页面。

前面的Docker Compose文件配置了一个带有名为demo的数据库(或模式;在MariaDB中它们是同义词)的MariaDB数据库服务器。它还创建了一个用户名为user、密码为Password123!的用户。该用户在demo数据库上有适当的权限。还有一个额外的用户,名为maxscale_user,密码为MaxScalePassword123!。这是MaxScale数据库代理用于连接到MariaDB数据库的用户。

Docker Compose文件还通过禁用HTTPS(在生产环境中不要这么做!)、暴露一组端口(稍后会详细讨论)以及配置数据库用户和MariaDB数据库代理的位置(通常是一个IP地址,但在这里我们可以使用在Docker文件中之前定义的容器的名称)来配置数据库代理。最后一行创建了一个NoSQL监听器,我们将使用它在默认端口(27017)上作为MongoDB客户端连接。

要使用命令行启动服务(容器),请移至保存Docker Compose文件的目录,并运行以下命令:

docker compose up -d

下载所有软件并启动容器后,你将拥有一个MariaDB数据库和MaxScale代理,两者都已预先配置为此实验。

在MariaDB中创建SQL表

首先,让我们连接到关系型数据库。在命令行中,执行以下命令:

perl 复制代码
mariadb-shell --dsn mariadb://user:'Password123!'@127.0.0.1

检查你是否可以看到demo数据库:

ini 复制代码
show databases;

切换到demo数据库:

ini 复制代码
use demo;

使用MariaDB Shell连接数据库

创建books表:​​​​​​​

sql 复制代码
CREATE TABLE books(  isbn VARCHAR(20) PRIMARY KEY,  title VARCHAR(256),  year INT);

插入一些数据。我打算使用陈词滥调的方法插入我的书:​​​​​​​

sql 复制代码
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);

通过运行以下命令,检查书籍是否存储在数据库中:

sql 复制代码
SELECT * FROM books;

使用MariaDB Shell插入数据

在MariaDB中创建一个JSON集合

我们还没有安装MongoDB,但我们可以使用一个MongoDB客户端(或应用程序)连接创建集合和文档,就好像我们正在使用MongoDB一样,只是数据存储在一个功能强大、完全支持ACID的可扩展关系型数据库中。让我们试试看!

在命令行中,使用MongoDB shell工具连接到MongoDB...等等...其实是MariaDB数据库!执行以下命令:

mongosh

默认情况下,此工具尝试连接到在你的本地机器(127.0.0.1)上运行的MongoDB服务器(这次恰好是MariaDB),使用默认端口(20017)。如果一切顺利,当你运行以下命令时,你应该能够看到demo数据库:

sql 复制代码
show databases

切换到demo数据库:

perl 复制代码
use demo

使用Mongo Shell连接到MariaDB

我们已经从一个非关系型客户端连接到了关系型数据库!现在,让我们创建评分集合并插入一些数据:

css 复制代码
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"  }])

检查评分是否已在数据库中保存:

lua 复制代码
db.ratings.find()

使用Mongo Shell查询MariaDB数据库

使用MariaDB中的JSON函数

此时,我们有一个单一的数据库,从外部看起来像一个NoSQL(MongoDB)数据库和一个关系型(MariaDB)数据库。我们能够连接到相同的数据库,并从MongoDB客户端和SQL客户端读写数据。所有数据都存储在MariaDB中,因此我们可以使用SQL将来自MongoDB客户端或应用的数据与来自MariaDB客户端或应用的数据进行连接。让我们探索MaxScale如何使用MariaDB存储MongoDB数据(集合和文档)。

使用像mariadb-shell这样的SQL客户端连接到数据库,并显示demo模式中的表:

ini 复制代码
show tables in demo;

你应该看到books和ratings表都列出了。ratings是作为MongoDB集合创建的。MaxScale转译了从MongoDB客户端发送的命令,并创建了一个表来存储数据。让我们看看这个表的结构:

ini 复制代码
describe demo.ratings;

一个NoSQL集合存储为MariaDB关系型表

ratings表包含两列:

  • id:对象ID。
  • doc:以JSON格式的文档。

如果我们查看表的内容,我们会看到关于ratings的所有数据都存储在以JSON格式的doc列中:

sql 复制代码
SELECT doc FROM demo.ratings \G

NoSQL文档存储在MariaDB数据库中

让我们回到我们的原始目标------显示书籍标题及其评分信息。以下情况并非如此,但让我们暂时假设ratings表是一个常规表,有stars和comment列。如果是这样的话,将此表与books表连接起来就很容易了,我们的工作就完成了:​​​​​​​

css 复制代码
/* this doesn't work */SELECT b.title, r.stars, r.commentFROM ratings rJOIN books b USING(isbn)

回到现实。我们需要将实际ratings表的doc列转换为查询中的新表的关系表达式。像这样:​​​​​​​

css 复制代码
/* this still doesn't work */SELECT b.title, r.stars, r.commentFROM ratings rtJOIN ...something to convert rt.doc to a table... AS rJOIN books b USING(isbn)

那个东西是JSON_TABLE函数。MariaDB包括一套全面的JSON函数用于操作JSON字符串。我们将使用JSON_TABLE函数将doc列转换为我们可以用来执行SQL连接的关系形式。JSON_TABLE函数的一般语法如下:​​​​​​​

scss 复制代码
JSON_TABLE(json_document, context_path COLUMNS (    column_definition_1,    column_definition_2,    ...  )) [AS] the_new_relational_table

其中:

  • json_document:要使用的返回JSON文档的字符串或表达式。
  • context_path:定义用作行源的节点的JSON Path表达式。

列定义(column_definition_1、column_definition_2等)具有以下语法:

css 复制代码
new_column_name sql_type PATH path_in_the_json_doc [on_empty] [on_error]

结合这些知识,我们的SQL查询将如下所示:​​​​​​​

sql 复制代码
SELECT b.title, r.stars, r.commentFROM ratings rtJOIN JSON_TABLE(rt.doc, '$' COLUMNS(    isbn VARCHAR(20) PATH '$.isbn',    stars INT PATH '$.starts',    comment TEXT PATH '$.comment'  )) AS rJOIN books b USING(isbn);

在一个SQL查询中连接NoSQL和SQL数据

我们本可以使用ISBN值作为MongoDB ObjectID,从而作为ratings表中的id列,但我会把这个留给你作为一个练习(提示:使用MongoDB客户端或应用插入数据时使用_id而不是isbn)。

关于可伸缩性的一点话

有一种误解,即关系型数据库不具有水平扩展性(添加更多节点),而NoSQL数据库具有。但是,关系型数据库在扩展时不牺牲ACID属性。MariaDB拥有多种存储引擎,适用于不同的工作负载。例如,您可以使用Spider来实现数据分片,从而扩展MariaDB数据库。您还可以使用各种存储引擎在每个表的基础上处理不同的工作负载。在单个SQL查询中都可以进行跨引擎连接。

在一个逻辑MariaDB数据库中结合多个存储引擎

另一个更现代的选择是使用MariaDB Xpand的分布式SQL。一个分布式SQL数据库通过透明的分片在应用程序中呈现为一个单一的逻辑关系型数据库。它采用无共享架构,可以扩展读写操作。

分布式SQL数据库部署

结论

我们的工作在这里完成了!现在,您的系统可以对独立于SQL或NoSQL应用程序创建的数据进行ACID兼容的可扩展的360度视图。减少了从NoSQL迁移到SQL的需求,或使SQL应用程序成为数据库多语言用户。

作者:Alejandro Duarte

更多技术干货请关注公众号 "云原生数据库"

squids.cn 目前可体验全网zui低价RDS,免费的迁移工具DBMotion、SQL开发工具等

相关推荐
Sunyanhui138 分钟前
牛客网 SQL36查找后排序
数据库·sql·mysql
Mitch3112 小时前
【漏洞复现】CVE-2021-45788 SQL Injection
sql·web安全·docker·prometheus·metersphere
网络安全King3 小时前
网络安全 - SQL Injection
sql·web安全·php
Stanford_11065 小时前
高级的SQL查询技巧有哪些?
sql·微信小程序·twitter·微信开放平台
wlyang6667 小时前
1. SQL常见笔试题目
数据库·sql
smilejingwei7 小时前
SQL,生成指定时间间隔内的事件次序号
数据库·sql·spl·esprocspl
张伯毅9 小时前
Flink SQL 支持 kafka 开启 kerberos 权限控制.
sql·flink·kafka
向阳12189 小时前
mybatis 动态 SQL
数据库·sql·mybatis
小黄人软件9 小时前
20241220流水的日报 mysql的between可以用于字符串 sql 所有老日期的,保留最新日期
数据库·sql·mysql
青莳吖9 小时前
Java通过Map实现与SQL中的group by相同的逻辑
java·开发语言·sql