Orientdb 简明教程
OrientDB - Hooks
OrientDB Hooks 不过是在数据库术语中触发器,它们启用在用户应用程序中的每个 CRUD 操作之前和之后的内部事件。您可以使用钩子来编写自定义验证规则,以强制执行安全性,或安排外部事件,比如对于关系 DBMS 进行复制。
OrientDB Hooks are nothing but triggers in the database terminology that enable internal events before and after each CRUD operations in the user applications. You can use hooks to write custom validation rules, to enforce security, or to arrange external events like replicating against a relational DBMS.
OrientDB 支持两种钩子 −
OrientDB supports two kinds of hooks −
Dynamic Hook − 触发器,可以在类级别和/或文档级别构建。
Dynamic Hook − Triggers, which can be built at class level and/or Document level.
Java (Native) Hook − 触发器,可以使用 Java 类构建。
Java (Native) Hook − Triggers, which can be built using Java classes.
Dynamic Hooks
动态钩子比 Java 钩子更灵活,因为它们可以在运行时更改并且可以在需要时针对每个文档运行,但是比 Java 钩子慢。
Dynamic hooks are more flexible than Java hooks, because they can be changed at runtime and can run per document if needed, but are slower than Java hooks.
要在您的文档上执行钩子,首先允许您的类扩展 OTriggered 基类。之后,为相关事件定义一个自定义属性。以下是可用的事件。
To execute hooks against your documents, first allow your classes to extend OTriggered base class. Later, define a custom property for the interested event. Following are the available events.
-
onBeforeCreate − Called before creating a new document.
-
onAfterCreate − Called after creating a new document.
-
onBeforeRead − Called before reading a document.
-
onAfterRead − Called after reading a document.
-
onBeforeUpdate − Called before updating a document.
-
onAfterUpdate − Called after updating a document.
-
onBeforeDelete − Called before deleting a document.
-
onAfterDelete − Called after deleting a document.
动态钩子可以调用 −
Dynamic Hooks can call −
-
Functions, written in SQL, Javascript or any language supported by OrientDB and JVM.
-
Java static methods.
Class Level Hooks
类级别钩子为与类相关的所有文件定义。以下示例设置一个在类级别下对发票文件起作用的钩子。
Class level hooks are defined for all the documents that relate to a class. Following is an example to set up a hook that acts at class level against Invoice documents.
CREATE CLASS Invoice EXTENDS OTriggered
ALTER CLASS Invoice CUSTOM onAfterCreate = invoiceCreated
让我们以 Javascript 编制函数 invoiceCreated ,用于在服务器控制台中打印创建的发票编号。
Let’s create the function invoiceCreated in Javascript that prints in the server console the invoice number created.
CREATE FUNCTION invoiceCreated "print('\\nInvoice created: ' + doc.field ('number'));"
LANGUAGE Javascript
现在通过创建新 Invoice 文件来尝试此钩子。
Now try the hook by creating a new Invoice document.
INSERT INTO Invoice CONTENT {number: 100, notes: 'This is a test}
如果成功执行此命令,您将得到以下输出。
If this command is executed successfully, you will get the following output.
Invoice created: 100
Document Level Hook
您只能针对一个或多个文件定义特别操作。为此,允许类扩展 OTriggered 类。
You can define a special action only against one or more documents. To do this, allow your class to extend OTriggered class.
例如,让我们针对现有 Profile 类的所有文件(带有 account = 'Premium' 属性)以 Javascript 函数形式执行一个触发器。此触发器将被调用以防止删除文件。
For example let us execute a trigger, as Javascript function, against an existent Profile class, for all the documents with property account = 'Premium'. The trigger will be called to prevent deletion of documents.
ALTER CLASS Profile SUPERCLASS OTriggered UPDATE Profile
SET onBeforeDelete = 'preventDeletion' WHERE account = 'Premium'
让我们创建 preventDeletion() Javascript 函数。
Let’s create the preventDeletion() Javascript function.
CREATE FUNCTION preventDeletion "throw new java.lang.RuntimeException('Cannot
delete Premium profile ' + doc)" LANGUAGE Javascript
然后通过尝试删除 “Premium” 帐户来测试钩子。
And then test the hook by trying to delete a ‘Premium’ account.
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 字段,在更新记录时使用该字段,并且可以采用在数据库层一次实现逻辑,无需在应用程序层再次考虑的方法来执行这些操作。
One common use case for OrientDB Hooks (triggers) is to manage created and updated dates for any or all classes. For example, you can set a CreatedDate field whenever a record is created and set an UpdatedDate field whenever a record is updated, and do it in a way where you implement the logic once at the database layer and never have to worry about it again at the application layer.
在创建之前,您将必须通过访问以下链接 download OrientDB core 下载 orientdb-core.jar 文件。然后将 JAR 文件复制到要存储 Java 源文件的文件夹中。
Before creating, you will have to download orientdb-core.jar file by visit the following link download OrientDB core. And later copy that jar file into the folder where you want to store the Java source file.
Create Hook File
创建一个名为 HookTest.java 的 Java 文件,该文件将使用 Java 语言测试钩子机制。
Create a Java file named HookTest.java, which will test the Hook mechanism using Java language.
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;
}
}
上述示例代码在每次创建或更新该类的记录时都会打印适当的注释。
The above sample code prints the appropriate comment every time you create or update a record of that class.
让我们再添加一个钩子文件 setCreatedUpdatedDates.java 如下:
Let’s add one more hook file setCreatedUpdatedDates.java as follows −
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。
What the above code does is look for any class that starts with the letters ‘r’ or ‘t’ and sets CreatedDate and UpdatedDate when the record gets created and sets just UpdatedDate every time the record gets updated.
Compile Java Hooks
使用以下命令编译 Java 代码。 Note :将下载的 JAR 文件和这些 Java 文件保留在同一个文件夹中。
Compile Java code by using the following command. Note: Keep the downloaded jar file and these Java files into the same folder.
$ jar cf hooks-1.0-SNAPSHOT.jar *.java
Move Compiled Code to Where OrientDB Server Can Find It
您需要将完成的 JAR 文件复制到 OrientDB 服务器将对其进行查找的目录中。这意味着 OrientDB 服务器根目录下的“ ./lib ”文件夹将如下所示:
You need to copy the finished .jar file to the directory where your OrientDB server will look for them. This means the ‘./lib’ folder under your OrientDB Server root directory will look like this −
$ 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 ,并添加以下部分到该文件的末尾:
Edit $ORIENTDB_HOME/config/orientdb-server-config.xml and add the following section near the end of the file.
<hooks>
<hook class = "HookTest" position = "REGULAR"/>
</hooks>
...
</orient-server>
Restart OrientDB Server
一旦重新启动 OrientDB 服务器,您在 orientdb-server-config.xml 中定义的钩子现在就处于活动状态。启动 OrientDB 控制台,将其连接到您的数据库,并运行以下命令:
Once you restart OrientDB Server, the hook you defined in orientdb-server-config.xml is now active. Launch an OrientDB console, connect it to your database, and run the following command −
INSERT INTO V SET ID = 1;
如果成功执行此命令,您将得到以下输出。
If this command is executed successfully, you will get the following output.
Ran create hook
现在,运行以下命令:
Now run the following command −
UPDATE V SET ID = 2 WHERE ID = 1;
如果成功执行此命令,您将得到以下输出。
If this command is executed successfully, you will get the following output.
Ran update hook
Enable Real Hook in the OrientDB Server Configuration File
编辑 $ORIENTDB_HOME/config/orientdb-server-config.xml ,并将钩子部分更改如下:
Edit $ORIENTDB_HOME/config/orientdb-server-config.xml and change the hooks section as follows −
<hooks>
<hook class="setCreatedUpdatedDates" position="REGULAR"/>
</hooks>
...
</orient-server>
Restart OrientDB Server
从字母“ r ”或“ t ”开始创建新类 -
Create a new class that starts with the letter ‘r’ or ‘t’ −
CREATE CLASS tTest EXTENDS V;
现在插入一条记录 -
Now insert a record −
INSERT INTO tTest SET ID = 1
SELECT FROM tTest
如果成功执行此命令,您将得到以下输出。
If this command is executed successfully, you will get the following output.
----+-----+------+----+-----------+-----------
# |@RID |@CLASS|ID |CreatedDate|UpdatedDate
----+-----+------+----+-----------+-----------
0 |#19:0|tTest |1 |1427597275 |1427597275
----+-----+------+----+-----------+-----------
即使您没有指定为 CreatedDate 和 UpdatedDate 设置的值,OrientDB 也已经为您自动设置了这些字段。
Even though you did not specify values to set for CreatedDate and UpdatedDate, OrientDB has set these fields automatically for you.
接下来,您需要使用以下命令更新记录 -
Next you need to update the record using the following command −
UPDATE tTest SET ID = 2 WHERE ID = 1;
SELECT FROM tTest;
如果成功执行此命令,您将得到以下输出。
If this command is executed successfully, you will get the following output.
----+-----+------+----+-----------+-----------
# |@RID |@CLASS|ID |CreatedDate|UpdatedDate
----+-----+------+----+-----------+-----------
0 |#19:0|tTest |2 |1427597275 |1427597306
----+-----+------+----+-----------+-----------
您会发现,OrientDB 已经更改了 UpdatedDate ,但未更改 CreatedDate 。
You can see that OrientDB has changed the UpdatedDate but has let the CreatedDate remain unchanged.
OrientDB Java Hooks 可能是极有价值的工具,可以帮助您自动完成本来需要在应用程序代码中完成的工作。由于许多 DBA 并不总是 Java 专家,因此希望本教程中包含的信息能为您提供良好的开端,并让您对这项技术充满信心,使您能够在需要时成功创建数据库触发器。
OrientDB Java Hooks can be an extremely valuable tool to help automate work you would otherwise have to do in application code. As many DBAs are not always Java experts, hopefully the information contained in this tutorial will give you a head start and make you feel comfortable with the technology, empowering you to successfully create database triggers as the need arises.