大势趋007

每个人都是🏆 时时刻刻::::: 1 新的技术经常性尝试,经常性测试;;;;; 2 一线dba的经常性操作和总结,二线技术的经常性思考
  新随笔  :: 管理

Oracle AI 数据库 JavaScript 开发者学习指南

Posted on 2026-01-22 10:47  大势趋007  阅读(0)  评论(0)    收藏  举报

Oracle AI 数据库 JavaScript 开发者学习指南

本文档旨在为使用 Oracle AI 数据库多语言引擎 (MLE) 的 JavaScript 开发者提供一份全面的学习指南。内容包括核心概念总结、关键代码案例、自我测验及答案解析,以及一个常用术语表,所有信息均提炼自官方开发者指南。

核心概念总结

Oracle AI 数据库通过其多语言引擎 (MLE) 将 JavaScript 的强大功能直接引入数据库层。这种“智能数据库 (Smart-DB)”方法将应用逻辑与数据并置,从而提升性能、增强安全性并简化数据处理模式。

1. 在数据库中调用 JavaScript

在数据库中执行 JavaScript 代码主要有两种方式:

  • 动态执行 (Dynamic Execution):通过 DBMS_MLE PL/SQL 包执行匿名的 JavaScript 代码片段。这种方式无需在数据库中持久化存储代码,适用于一次性或动态生成的脚本。工作流程包括创建执行上下文、提供 JavaScript 源代码 (作为 CLOB 或 VARCHAR2)、执行代码,最后销毁上下文。
  • MLE 模块调用 (MLE Module Calls):将 JavaScript 代码创建为持久化的数据库模式对象,即 MLE 模块。通过为模块中导出的函数创建调用规范 (Call Specification),可以使这些 JavaScript 函数像普通的 PL/SQL 过程或函数一样被 SQL 和 PL/SQL 调用。这是构建可重用、模块化业务逻辑的首选方法。

2. MLE 模块与环境

  • MLE 模块 (MLE Modules)
    • 它们是存储在数据库中的模式对象,包含遵循 ECMAScript 6 (ES6) 模块标准的 JavaScript 代码。
    • 使用 CREATE MLE MODULE DDL 语句进行创建。
    • 模块内的函数、类或变量必须使用 export 关键字导出,才能被外部调用或被其他模块导入。
    • 未导出的标识符被视为模块私有。
  • MLE 环境 (MLE Environments)
    • 它们是补充 MLE 模块的模式对象,用于自定义 JavaScript 运行时。
    • 主要功能包括:
      1. 名称解析:在 import 语句中,将导入名称映射到具体的 MLE 模块。这是实现模块化代码的关键。
      2. 设置语言选项:例如,通过设置 'js.strict=true' 来强制执行 JavaScript 的严格模式。

3. 调用规范 (Call Specifications)

调用规范是连接 PL/SQL/SQL 世界与 JavaScript 世界的桥梁。它将一个 PL/SQL 过程或函数映射到一个 JavaScript 函数。

  • 模块调用规范
    • 语法为 CREATE ... AS MLE MODULE module_name SIGNATURE 'js_function_name(types)'
    • MODULE 子句指定目标 MLE 模块。
    • SIGNATURE 子句指定要调用的已导出 JavaScript 函数的名称及其参数类型。
  • 内联调用规范
    • 语法为 CREATE ... AS MLE LANGUAGE JAVASCRIPT {{ ... }}
    • 允许将 JavaScript 函数体直接嵌入 DDL 语句中,无需创建单独的 MLE 模块。
    • 适用于实现简单的、非重用的功能。
    • 内联代码无法导入其他 MLE 模块,但可以通过全局变量访问内置模块的功能。

4. 从 JavaScript 调用 SQL 与 PL/SQL

MLE 提供了一套强大的 API,使 JavaScript 代码能够无缝地与数据库交互。

  • MLE JavaScript SQL 驱动 (mle-js-oracledb)
    • 这是一个内置模块,其 API 设计与流行的 Node.js 驱动 node-oracledb 高度相似,但核心区别在于 mle-js-oracledb 默认以同步方式运行
    • 常用的对象如 oracledb (驱动对象) 和 session (默认连接对象) 可作为全局变量直接使用,简化了代码。
    • 通过 session.execute() 方法执行 SQL 查询、DML 和 PL/SQL 匿名块。
  • 绑定变量 (Bind Variables)
    • 强烈推荐使用绑定变量(而非字符串拼接)来构建 SQL 语句,这对于提升性能和防止 SQL 注入至关重要。
    • 支持按名称绑定(使用 JavaScript 对象)和按位置绑定(使用数组)。
  • 外部函数接口 (FFI - Foreign Function Interface)
    • mle-js-plsql-ffi 模块提供,它允许将 PL/SQL 包、过程和函数作为 JavaScript 对象进行操作。
    • 相比于通过 session.execute() 调用 PL/SQL,FFI 提供了更自然、更简洁的 JavaScript 语法。

5. 使用 SODA 集合

  • SODA (Simple Oracle Document Access) 是一套 NoSQL 风格的 API,用于在 Oracle 数据库中创建和管理文档集合,特别是 JSON 文档。
  • 开发者无需了解 SQL 即可对文档执行创建、读取、更新和删除 (CRUD) 操作。
  • 在 MLE JavaScript 中,可以通过全局的 soda 对象(代表 SodaDatabase)轻松访问 SODA 功能。
  • 核心对象包括 SodaDatabaseSodaCollection(文档集合)和 SodaDocument(单个文档)。

6. 安全性考量

  • 受限执行上下文 (Restricted Execution Context)
    • 通过在 MLE 环境或内联调用规范中指定 PURE 关键字来启用。
    • PURE 上下文中运行的 JavaScript 代码无法访问任何数据库状态,如读写表、调用存储过程等。它只能通过函数参数接收输入并通过返回值提供输出。
    • 这为运行第三方库或执行纯计算任务提供了一个强大的安全沙箱,显著减小了供应链攻击的风险。
    • PURE 模式下,mle-js-oracledbmle-js-plsql-ffimle-js-fetch 等与数据库状态交互的 API 均不可用。

关键案例

以下案例展示了在 Oracle AI 数据库中使用 JavaScript 的常见模式。

案例 1:创建并使用 MLE 模块

此案例创建一个计算订单总价值的 MLE 模块,并为其创建一个 PL/SQL 函数调用规范。

-- 步骤 1: 创建一个 MLE 模块,导出一个函数
CREATE OR REPLACE MLE MODULE po_module LANGUAGE JAVASCRIPT AS
/**
 * get the value of all line items in an order
 * @param {array} lineItems - all the line items in a purchase order
 * @returns {number} the total value of all line items in a purchase order
 */
export function orderValue(lineItems) {
    return lineItems
        .map(x => x.Part.UnitPrice * x.Quantity)
        .reduce(
            (accumulator, currentValue) => accumulator + currentValue, 0
        );
}
/

-- 步骤 2: 为导出的 JavaScript 函数创建一个调用规范
CREATE OR REPLACE FUNCTION order_value(
    p_line_items JSON
) RETURN NUMBER
AS MLE MODULE po_module
SIGNATURE 'orderValue';
/

-- 步骤 3: 在 SQL 中调用该函数 (假设存在 j_purchaseorder 表)
SELECT
    po.po_document.PONumber,
    order_value(po.po_document.LineItems[*]) AS total_value
FROM
    j_purchaseorder po;

案例 2:创建内联调用规范

此案例展示了如何使用内联调用规范创建一个将时间戳转换为 Epoch 时间(自1970年1月1日以来的毫秒数)的函数。

CREATE OR REPLACE FUNCTION date_to_epoch(
  "theDate" TIMESTAMP WITH TIME ZONE
) RETURN NUMBER
AS MLE LANGUAGE JAVASCRIPT {{
  const d = new Date(theDate);

  // 检查输入参数是否为有效日期
  if (isNaN(d)){
    throw new Error(`${theDate} is not a valid date`);
  }

  // Date.prototype.getTime() 返回毫秒数
  return d.getTime();
}};
/

-- 在 SQL 中调用
SELECT date_to_epoch(SYSTIMESTAMP) FROM DUAL;

9326657b-733d-4fdc-9cf4-db932b7c5c58

 

案例 3:使用 MLE JavaScript SQL 驱动查询数据

此案例使用简化的内联调用规范和全局 session 对象来查询 hr.departments 表。

CREATE OR REPLACE PROCEDURE js_sql_mod_simplified(
    "managerID" number
) AS MLE LANGUAGE JAVASCRIPT {{
    if (managerID === undefined || managerID === null) {
        throw new Error(
            "Parameter managerID has not been provided"
        );
    }

    const result = session.execute(
        `SELECT
            manager_id,
            department_id,
            department_name
        FROM
            hr.departments
        WHERE
            manager_id = :id`,
        [managerID] // 使用位置绑定
    );

    if (result.rows.length > 0) {
        for (let row of result.rows) {
            console.log(
                `Found: manager_id: ${row.MANAGER_ID}, department_name: ${row.DEPARTMENT_NAME}`
            );
        }
    } else {
        console.log(`no data found for manager ID ${managerID}`);
    }
}};
/

-- 执行该过程
SET SERVEROUTPUT ON;
EXEC js_sql_mod_simplified(100);

案例 4:SODA 基本工作流

此案例展示了使用 SODA 的完整流程:创建集合、插入 JSON 文档、查找并显示文档,最后清理。

CREATE OR REPLACE PROCEDURE intro_soda(
    "dropCollection" BOOLEAN
) AUTHID CURRENT_USER AS MLE LANGUAGE JAVASCRIPT {{
    // 使用全局 soda 对象创建或打开一个集合
    const col = soda.createCollection("MyCollection");

    // 创建一个 JSON 文档
    const doc = {
        "_id": 100,
        "job_id": "AD_PRES",
        "last_name": "King",
        "first_name": "Steven"
    };

    // 将文档插入集合
    col.insertOne(doc);

    // 查找集合中的所有文档并打印
    const c = col.find().getCursor();
    let resultDoc;
    while (resultDoc = c.getNext()) {
        const content = resultDoc.getContent();
        console.log(`Key: ${resultDoc.key}, Name: ${content.first_name} ${content.last_name}`);
    }
    c.close(); // 必须关闭游标

    // 可选:删除集合
    if (dropCollection) {
        session.commit(); // 删除前必须提交事务
        col.drop();
    }
}};
/

-- 执行该过程
SET SERVEROUTPUT ON;
EXEC intro_soda(true);

自我测验

请根据以上内容和您的理解回答以下问题。

  1. 在 Oracle AI 数据库中执行 JavaScript 代码的两种主要方法是什么?
  2. PURE 关键字在创建 MLE 环境或内联调用规范时有什么作用?
  3. 用于将 JavaScript 函数发布以便从 SQL 和 PL/SQL 调用的数据库对象是什么?
  4. 在 MLE JavaScript 中,哪个内置模块提供了用于执行 SQL 语句的驱动程序?
  5. 与客户端的 node-oracledb 驱动程序相比,mle-js-oracledb 驱动程序在执行模式上的主要区别是什么?
  6. SODA 是什么?它主要用于处理哪种类型的数据?
  7. 在 MLE 模块中,如何使一个函数或变量可以被其他模块导入或通过调用规范使用?
  8. 什么是 MLE 环境 (MLE Environment)?它有两个主要功能是什么?
  9. 外部函数接口 (FFI) 的主要目的是什么?
  10. 当使用 session.execute() 执行 DML 语句(如 INSERT、UPDATE)后,事务会自动提交吗?

--------------------------------------------------------------------------------

答案与解析

  1. 答案:动态执行 (通过 DBMS_MLE 包) 和 MLE 模块调用 (通过创建持久化的 MLE 模块和调用规范)。 解析:动态执行适用于临时代码,而模块调用适用于构建可重用的、结构化的应用程序逻辑。
  2. 答案:它会创建一个受限的执行上下文,禁止 JavaScript 代码访问任何数据库状态(如表、过程、对象等),从而提供一个安全沙箱。 解析PURE 是一个重要的安全特性,尤其适用于运行第三方库或执行纯计算逻辑,可以防止意外或恶意的数据库操作。
  3. 答案:调用规范 (Call Specification)。 解析:调用规范是 PL/SQL 过程或函数,其实现指向一个 MLE 模块中的 JavaScript 函数或直接内联了 JavaScript 代码。
  4. 答案mle-js-oracledb解析:该模块提供了与数据库交互的核心功能,如获取连接和执行 SQL 语句。
  5. 答案mle-js-oracledb 默认是同步执行的,而 node-oracledb异步的(使用回调或 Promise/async/await)。 解析:由于 mle-js-oracledb 在数据库内部运行,不存在网络延迟,因此同步模型更直观、更简单。
  6. 答案:SODA (Simple Oracle Document Access) 是一套 NoSQL 风格的 API,主要用于处理数据库中存储的 JSON 文档解析:SODA 让开发者可以方便地对 JSON 文档集合执行 CRUD 操作,而无需编写 SQL。
  7. 答案:使用 export 关键字。 解析:这遵循 ECMAScript 6 模块标准。只有被导出的标识符才能在模块外部被访问。
  8. 答案:MLE 环境是一个模式对象,其主要功能是:1) 为 import 语句提供名称解析,将其映射到具体的 MLE 模块;2) 设置 JavaScript 运行时的语言选项。 解析:环境是组织和配置模块化 JavaScript 代码的关键组件。
  9. 答案:提供一种比执行原生 SQL 字符串更直接、更像原生 JavaScript 调用的方式来访问 PL/SQL 包、过程和函数。 解析:FFI (通过 mle-js-plsql-ffi 模块) 减少了模板代码,使 PL/SQL 调用在 JavaScript 中看起来更自然。
  10. 答案:不会。 解析mle-js-oracledb 驱动程序没有自动提交功能。事务管理与标准的 PL/SQL 行为一致,需要显式地通过 session.commit()session.rollback() 或在调用方的 PL/SQL 代码中进行提交或回滚。

术语表

术语

中文

描述

MLE (Multilingual Engine)

多语言引擎

Oracle AI 数据库的一项功能,允许在数据库内部直接执行多种编程语言的代码,如 JavaScript。

Dynamic Execution

动态执行

通过 DBMS_MLE PL/SQL 包执行临时的、非持久化的 JavaScript 代码片段。

MLE Module

MLE 模块

一个存储在数据库中的模式对象,包含可重用的 JavaScript (ECMAScript 6) 代码。

MLE Environment

MLE 环境

一个模式对象,用于配置 MLE 模块的运行时行为,主要是为了模块导入的名称解析和设置语言选项。

Call Specification

调用规范

一个 PL/SQL 过程或函数,其定义链接到一个 JavaScript 函数,使其可以从 SQL 或 PL/SQL 中调用。

SIGNATURE Clause

SIGNATURE 子句

在调用规范中,用于指定要调用的 JavaScript 函数名称及其参数类型的子句。

mle-js-oracledb

-

MLE 内置的 JavaScript SQL 驱动程序,用于从 JavaScript 代码中执行 SQL 和 PL/SQL。

FFI (Foreign Function Interface)

外部函数接口

一种 API (mle-js-plsql-ffi),允许以更自然、面向对象的方式从 JavaScript 直接调用 PL/SQL 程序单元。

SODA (Simple Oracle Document Access)

简单 Oracle 文档访问

一套 NoSQL 风格的 API,用于在 Oracle 数据库中管理 JSON 文档集合。

Restricted / PURE Context

受限 / PURE 上下文

一种安全的执行环境,通过 PURE 关键字启用,禁止 JavaScript 代码访问数据库状态,只能进行纯计算。

Bind Variables

绑定变量

在 SQL 语句中使用的占位符,用于安全、高效地传递数据。可以防止 SQL 注入并提高性能。