Orientdb 简明教程

OrientDB - Hooks

OrientDB Hooks 不过是在数据库术语中触发器,它们启用在用户应用程序中的每个 CRUD 操作之前和之后的内部事件。您可以使用钩子来编写自定义验证规则,以强制执行安全性,或安排外部事件,比如对于关系 DBMS 进行复制。

OrientDB 支持两种钩子 −

Dynamic Hook − 触发器,可以在类级别和/或文档级别构建。

Java (Native) Hook − 触发器,可以使用 Java 类构建。

Dynamic Hooks

动态钩子比 Java 钩子更灵活,因为它们可以在运行时更改并且可以在需要时针对每个文档运行,但是比 Java 钩子慢。

要在您的文档上执行钩子,首先允许您的类扩展 OTriggered 基类。之后,为相关事件定义一个自定义属性。以下是可用的事件。

  1. onBeforeCreate − 在 before 创建新文档时调用。

  2. onAfterCreate − 在 after 创建新文档时调用。

  3. onBeforeRead − 在 before 读取文档时调用。

  4. onAfterRead − 在 after 读取文档时调用。

  5. onBeforeUpdate − 在 before 更新文档时调用。

  6. onAfterUpdate − 在 after 更新文档时调用。

  7. onBeforeDelete − 在 before 删除文档时调用。

  8. onAfterDelete − 在 after 删除文档时调用。

动态钩子可以调用 −

  1. 函数,用 SQL、JavaScript 或 OrientDB 和 JVM 支持的任何语言编写。

  2. Java static methods.

Class Level Hooks

类级别钩子为与类相关的所有文件定义。以下示例设置一个在类级别下对发票文件起作用的钩子。

CREATE CLASS Invoice EXTENDS OTriggered
ALTER CLASS Invoice CUSTOM onAfterCreate = invoiceCreated

让我们以 Javascript 编制函数 invoiceCreated ,用于在服务器控制台中打印创建的发票编号。

CREATE FUNCTION invoiceCreated "print('\\nInvoice created: ' + doc.field ('number'));"
LANGUAGE Javascript

现在通过创建新 Invoice 文件来尝试此钩子。

INSERT INTO Invoice CONTENT {number: 100, notes: 'This is a test}

如果成功执行此命令,您将得到以下输出。

Invoice created: 100

Document Level Hook

您只能针对一个或多个文件定义特别操作。为此,允许类扩展 OTriggered 类。

例如,让我们针对现有 Profile 类的所有文件(带有 account = 'Premium' 属性)以 Javascript 函数形式执行一个触发器。此触发器将被调用以防止删除文件。

ALTER CLASS Profile SUPERCLASS OTriggered UPDATE Profile
SET onBeforeDelete = 'preventDeletion' WHERE account = 'Premium'

让我们创建 preventDeletion() Javascript 函数。

CREATE FUNCTION preventDeletion "throw new java.lang.RuntimeException('Cannot
delete Premium profile ' + doc)" LANGUAGE Javascript

然后通过尝试删除 “Premium” 帐户来测试钩子。

DELETE FROM #12:1
java.lang.RuntimeException: Cannot delete Premium profile
profile#12:1{onBeforeDelete:preventDeletion,account:Premium,name:Jill} v-1
(<Unknown source>#2) in <Unknown source> at line number 2

JAVA Hooks

OrientDB 钩子(触发器)的一个常见用例是管理任何或所有类的创建和更新日期。例如,可以设置一个 CreatedDate 字段,在创建记录时使用该字段,设置一个 UpdatedDate 字段,在更新记录时使用该字段,并且可以采用在数据库层一次实现逻辑,无需在应用程序层再次考虑的方法来执行这些操作。

在创建之前,您将必须通过访问以下链接 download OrientDB core 下载 orientdb-core.jar 文件。然后将 JAR 文件复制到要存储 Java 源文件的文件夹中。

Create Hook File

创建一个名为 HookTest.java 的 Java 文件,该文件将使用 Java 语言测试钩子机制。

import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.locks.ReentrantLock;
import com.orientechnologies.orient.core.hook.ODocumentHookAbstract;
import com.orientechnologies.orient.core.hook.ORecordHook;
import com.orientechnologies.orient.core.hook.ORecordHookAbstract;
import com.orientechnologies.orient.core.db.ODatabaseLifecycleListener;
import com.orientechnologies.orient.core.db.ODatabase;
import com.orientechnologies.orient.core.record.ORecord;
import com.orientechnologies.orient.core.record.impl.ODocument;

public class HookTest extends ODocumentHookAbstract implements ORecordHook {
   public HookTest() {

   }

   @Override
   public DISTRIBUTED_EXECUTION_MODE getDistributedExecutionMode() {
      return DISTRIBUTED_EXECUTION_MODE.BOTH;
   }
   public RESULT onRecordBeforeCreate( ODocument iDocument ) {
      System.out.println("Ran create hook");
      return ORecordHook.RESULT.RECORD_NOT_CHANGED;
   }
   public RESULT onRecordBeforeUpdate( ODocument iDocument ) {
      System.out.println("Ran update hook");
      return ORecordHook.RESULT.RECORD_NOT_CHANGED;
   }
}

上述示例代码在每次创建或更新该类的记录时都会打印适当的注释。

让我们再添加一个钩子文件 setCreatedUpdatedDates.java 如下:

import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.locks.ReentrantLock;
import com.orientechnologies.orient.core.hook.ODocumentHookAbstract;
import com.orientechnologies.orient.core.hook.ORecordHook;
import com.orientechnologies.orient.core.hook.ORecordHookAbstract;
import com.orientechnologies.orient.core.db.ODatabaseLifecycleListener;
import com.orientechnologies.orient.core.db.ODatabase;
import com.orientechnologies.orient.core.record.ORecord;
import com.orientechnologies.orient.core.record.impl.ODocument;

public class setCreatedUpdatedDates extends ODocumentHookAbstract implements ORecordHook {
   public setCreatedUpdatedDates() {

   }

   @Override
   public DISTRIBUTED_EXECUTION_MODE getDistributedExecutionMode() {
      return DISTRIBUTED_EXECUTION_MODE.BOTH;
   }
   public RESULT onRecordBeforeCreate( ODocument iDocument ) {
      if ((iDocument.getClassName().charAt(0) == 't') || (iDocument.getClassName().charAt(0)=='r')) {
         iDocument.field("CreatedDate", System.currentTimeMillis() / 1000l);
         iDocument.field("UpdatedDate", System.currentTimeMillis() / 1000l);
         return ORecordHook.RESULT.RECORD_CHANGED;
      } else {
         return ORecordHook.RESULT.RECORD_NOT_CHANGED;
      }
   }

   public RESULT onRecordBeforeUpdate( ODocument iDocument ) {
      if ((iDocument.getClassName().charAt(0) == 't') || (iDocument.getClassName().charAt(0)=='r')) {
         iDocument.field("UpdatedDate", System.currentTimeMillis() / 1000l);
         return ORecordHook.RESULT.RECORD_CHANGED;
      } else {
         return ORecordHook.RESULT.RECORD_NOT_CHANGED;
      }
   }
}

以上代码所做的是查找任何以字母“ r ”或“ t ”开头的类,并在该记录创建时设置 CreatedDate 和 UpdatedDate,并在每次更新该记录时仅设置 UpdatedDate。

Compile Java Hooks

使用以下命令编译 Java 代码。 Note :将下载的 JAR 文件和这些 Java 文件保留在同一个文件夹中。

$ jar cf hooks-1.0-SNAPSHOT.jar *.java

Move Compiled Code to Where OrientDB Server Can Find It

您需要将完成的 JAR 文件复制到 OrientDB 服务器将对其进行查找的目录中。这意味着 OrientDB 服务器根目录下的“ ./lib ”文件夹将如下所示:

$ cp hooks-1.0-SNAPSHOT.jar "$ORIENTDB_HOME/lib"

Enable Test Hook in the OrientDB Server Configuration File

编辑 $ORIENTDB_HOME/config/orientdb-server-config.xml ,并添加以下部分到该文件的末尾:

   <hooks>
      <hook class = "HookTest" position = "REGULAR"/>
   </hooks>
   ...
</orient-server>

Restart OrientDB Server

一旦重新启动 OrientDB 服务器,您在 orientdb-server-config.xml 中定义的钩子现在就处于活动状态。启动 OrientDB 控制台,将其连接到您的数据库,并运行以下命令:

INSERT INTO V SET ID = 1;

如果成功执行此命令,您将得到以下输出。

Ran create hook

现在,运行以下命令:

UPDATE V SET ID = 2 WHERE ID = 1;

如果成功执行此命令,您将得到以下输出。

Ran update hook

Enable Real Hook in the OrientDB Server Configuration File

编辑 $ORIENTDB_HOME/config/orientdb-server-config.xml ,并将钩子部分更改如下:

   <hooks>
      <hook class="setCreatedUpdatedDates" position="REGULAR"/>
   </hooks>
   ...
</orient-server>

Restart OrientDB Server

从字母“ r ”或“ t ”开始创建新类 -

CREATE CLASS tTest EXTENDS V;

现在插入一条记录 -

INSERT INTO tTest SET ID = 1
SELECT FROM tTest

如果成功执行此命令,您将得到以下输出。

----+-----+------+----+-----------+-----------
#   |@RID |@CLASS|ID  |CreatedDate|UpdatedDate
----+-----+------+----+-----------+-----------
0   |#19:0|tTest |1   |1427597275 |1427597275
----+-----+------+----+-----------+-----------

即使您没有指定为 CreatedDateUpdatedDate 设置的值,OrientDB 也已经为您自动设置了这些字段。

接下来,您需要使用以下命令更新记录 -

UPDATE tTest SET ID = 2 WHERE ID = 1;
SELECT FROM tTest;

如果成功执行此命令,您将得到以下输出。

----+-----+------+----+-----------+-----------
#   |@RID |@CLASS|ID  |CreatedDate|UpdatedDate
----+-----+------+----+-----------+-----------
0   |#19:0|tTest |2   |1427597275 |1427597306
----+-----+------+----+-----------+-----------

您会发现,OrientDB 已经更改了 UpdatedDate ,但未更改 CreatedDate

OrientDB Java Hooks 可能是极有价值的工具,可以帮助您自动完成本来需要在应用程序代码中完成的工作。由于许多 DBA 并不总是 Java 专家,因此希望本教程中包含的信息能为您提供良好的开端,并让您对这项技术充满信心,使您能够在需要时成功创建数据库触发器。