实体引擎的一个主要目标是尽可能提供一种通用的代码结构,来消除各模块中事务处理过程中的相近或相似的代码。这种抽象在于数据库数据操作逻辑的提取。它可以大大减少应用系统的开发费用和潜在的事务处理bug。在Ofbiz的实体引擎中,将存储实体属性值的类结构设计成通用的数据结构,使用一个MAP对象来作为数据载体来存取实体的所有属性值。实体引擎和应用系统之间的接口体现在实体结构定义文件和SQL字段类型与Java数据类型映射关系定义中(以XML文件方式进行描述)。基于这个抽象层,使用实体引擎提供的API来处理实体持久化操作。
取代编写特定的代码,实体的定义是在entitymodel*.XML文件中完成的,并由实体引擎强制规定应用系统和数据源之间的访问规则。在实体文件entitymodel*.XML中定义了实体和实体的关系,包含一个相关联的数据库表和关系类型(one or many),以及关系的关键字值对。关系可以定义一个标识来区别实体关系中的其他关系。
SQL语句执行引擎
实体引擎中的一个重要组成部分就是SQL语句的执行引擎。在Ofbiz中,SQL语句执行引擎的中心是SQLProcessor类,每一个GenericDAO执行一个Add/Update/Delete操作时,都会创建一个SQLProcessor执行器,SQLProcessor执行器会从ConnectionFactory中取得一个数据库连接。
在上图中,SqlJDBCUtil描述了数据库类型与Java类型间的映射关系,以及建立表间关系或View的方法。TransactionUtil则提供了一系列事务管理的静态方法。
数据库连接是由一个数据库连接池来进行管理,如下图:
接口定义
我的理解,Ofbiz中的数据模型应是充血模型,在Domain Object中包含了业务逻辑和持久化,GenericDAO仅作为基础设施层,实现对业务对象的持久化的作用。
数据模型定义如下:
GenericPK类是模型的描述,它联系entitymodel.xml文件中所描述的模型转为应用中的类型定义。entitymodel.xml中的模型描述信息装载在ModelEntity类中。GenericValue则是模型对象的一个实例。
GenericHelperDAO是GenericHelper接口的一个实现,实现了DAO层功能。具体应用GenericDAO类来执行SQL。在GenericDAO类中引用了一个SQLPrococessor类来完成与DB的交互。
Delegator则是一个服务层代表。
实体引擎的过滤功能实现:由三个部分组成:EntityConditionValue、EntityOperator、EntityCondition。这些过滤类将在GenericDAO中被转化为相应的SQL语句执行。
主键生成策略
主键是通过SequenceUtil来生成的,它仅在GenericDelegator中被使用。实现机制是在内存中保存表的当前序列号,当创建新的ID时,依据当前序列通过计算得到下一条序列。当出现错误时,强制重新从表中查询出当前序列号保存在内存中,作为下一次计算的依据。
算法如下:
private synchronized Long getNextSeqId(long staggerMax) {
long stagger = 1;
if (staggerMax > 1) {
stagger = Math.round(Math.random() * staggerMax);
if (stagger == 0) stagger = 1;
}
if ((curSeqId + stagger) <= maxSeqId) {
Long retSeqId = Long.valueOf(curSeqId);
curSeqId += stagger;
return retSeqId;
} else {
fillBank(stagger);
if ((curSeqId + stagger) <= maxSeqId) {
Long retSeqId = Long.valueOf(curSeqId);
curSeqId += stagger;
return retSeqId;
} else {
Debug.logError(“[SequenceUtil.SequenceBank.getNextSeqId] Fill bank failed, returning null”, module);
return null;
}
}
}
流程
实体引擎动作示意图:
每个特定的GenericHelper的配置信息都在entityengine.xml文件的datsource元素指定。
依赖别人的人等于折断了自己的翅膀,永远也体会不到飞翔的快乐。